├── assets
└── ContentView.png
├── DataFlow
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Preview Content
│ ├── Preview Assets.xcassets
│ │ └── Contents.json
│ └── PersonVMTestData.swift
├── Environment
│ ├── UserSettings.swift
│ ├── CustomModifiers.swift
│ ├── ChildView.swift
│ ├── NestingViews.swift
│ └── GrandChildView.swift
├── Property.swift
├── UsingState.swift
├── State & Binding 2
│ ├── Pizza.swift
│ └── PizzaView.swift
├── Observable 1
│ ├── ColorSet.swift
│ ├── ColorSetView.swift
│ └── ColorChooser.swift
├── AppDelegate.swift
├── Base.lproj
│ └── LaunchScreen.storyboard
├── State & Binding 1
│ └── Numbers.swift
├── Info.plist
├── ContentView.swift
├── Observable 2
│ ├── PersonDetailView.swift
│ ├── PersonListView.swift
│ └── PersonListModel.swift
└── SceneDelegate.swift
├── README.md
└── DataFlow.xcodeproj
├── project.xcworkspace
├── contents.xcworkspacedata
├── xcuserdata
│ └── sarah.xcuserdatad
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── xcuserdata
└── sarah.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
└── project.pbxproj
/assets/ContentView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trozware/swiftui-data-flow/HEAD/assets/ContentView.png
--------------------------------------------------------------------------------
/DataFlow/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DataFlow/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwiftUI Data Flow
2 |
3 | An Xcode project for use with https://troz.net/post/2019/swiftui-data-flow/
4 |
5 | Demonstrating multiple ways of passing data around a SwiftUI app.
6 |
7 | 
--------------------------------------------------------------------------------
/DataFlow.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DataFlow.xcodeproj/xcuserdata/sarah.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/DataFlow.xcodeproj/project.xcworkspace/xcuserdata/sarah.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/DataFlow.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DataFlow/Environment/UserSettings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserSettings.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 15/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // An EnvironmentObject class is just like any ObservableObject class
12 |
13 | class UserSettings: ObservableObject {
14 | @Published var isLoggedIn: Bool = false
15 | }
16 |
--------------------------------------------------------------------------------
/DataFlow.xcodeproj/xcuserdata/sarah.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DataFlow.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/DataFlow/Property.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Property.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 16/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct Property: View {
12 | // Property
13 | let greeting = "Hello from SwiftUI!"
14 |
15 | var body: some View {
16 | // Using property directly
17 | Text(greeting)
18 | .font(.title)
19 | }
20 | }
21 |
22 | struct Property_Previews: PreviewProvider {
23 | static var previews: some View {
24 | Property()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DataFlow/UsingState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsingState.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 16/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct UsingState: View {
12 | @State private var toggleValue = true
13 |
14 | var body: some View {
15 | // Using state with 2-way binding
16 | Toggle(isOn: $toggleValue) {
17 | Text("Toggle is \(toggleValue ? "ON" : "OFF")")
18 | }
19 | .padding(50)
20 | }
21 | }
22 |
23 | struct UsingState_Previews: PreviewProvider {
24 | static var previews: some View {
25 | UsingState()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/DataFlow/Environment/CustomModifiers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomModifiers.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 15/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | // A custom view modifier so all the buttons can look the same
12 | // without having to enter this amount of detail every time
13 |
14 | struct GrayButtonStyle: ViewModifier {
15 | func body(content: Content) -> some View {
16 | return content
17 | .frame(width: 150, height: 40)
18 | .padding()
19 | .font(.title)
20 | .background(Color.gray)
21 | .foregroundColor(.white)
22 | .cornerRadius(20)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DataFlow/State & Binding 2/Pizza.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Pizza.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // Pizza model based on enums for each property
12 | // All CaseIterable so they can be looped through to create the UI
13 |
14 | struct Pizza {
15 | var name: PizzaName = .margherita
16 | var size: PizzaSize = .medium
17 | var crust: PizzaCrust = .standard
18 |
19 | var pizzaSelection: String {
20 | return "You have selected a \(size.rawValue) \(name.rawValue.capitalized) pizza with a \(crust.rawValue) crust."
21 | }
22 | }
23 |
24 | enum PizzaName: String, CaseIterable {
25 | case margherita, hawaiian, pepperoni, vegetarian, seafood, mushroom
26 | }
27 |
28 | enum PizzaSize: String, CaseIterable {
29 | case small, medium, large
30 | }
31 |
32 | enum PizzaCrust: String, CaseIterable {
33 | case thin, standard, deeppan = "deep pan"
34 | }
35 |
--------------------------------------------------------------------------------
/DataFlow/Observable 1/ColorSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorSet.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 17/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | class ColorSet: ObservableObject {
12 |
13 | // ObservableObject
14 | // The 6 color components are marked as @Published so any changes
15 | // get published to the views that are observing
16 |
17 | @Published var foregroundRed = 0.0
18 | @Published var foregroundGreen = 0.0
19 | @Published var foregroundBlue = 0.0
20 |
21 | @Published var backgroundRed = 1.0
22 | @Published var backgroundGreen = 1.0
23 | @Published var backgroundBlue = 1.0
24 |
25 | // Computed variables to create the RGB colors from the components
26 |
27 | var foregroundColor: Color {
28 | return Color(red: foregroundRed, green: foregroundGreen, blue: foregroundBlue)
29 | }
30 |
31 | var backgroundColor: Color {
32 | return Color(red: backgroundRed, green: backgroundGreen, blue: backgroundBlue)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/DataFlow/Preview Content/PersonVMTestData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PersonVMTestData.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 22/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension PersonViewModel {
12 | // Sample data for use in Previews only
13 |
14 | static func samplePerson() -> PersonViewModel {
15 | let json = """
16 | {
17 | "id": "07534800-9c07-4857-b931-d6541ff0df08",
18 | "first": "Beasley",
19 | "last": "Burnett",
20 | "phone": "+1 (957) 453-3538",
21 | "address": "740 Jodie Court, Manchester, Vermont, 8934",
22 | "registered": "2018-06-08T01:08:31+00:00"
23 | }
24 | """
25 |
26 | let jsonDecoder = JSONDecoder()
27 | jsonDecoder.dateDecodingStrategy = .iso8601
28 |
29 | // Uisng force un-wrapping for sample data only, not for production
30 | let person = try! jsonDecoder.decode(PersonModel.self, from: json.data(using: .utf8)!)
31 | return PersonViewModel(with: person)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/DataFlow/Environment/ChildView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChildView.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 15/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ChildView: View {
12 | // Because this view does not use the data, there is no need to pass
13 | // it down to it, but its child can still access that data.
14 |
15 | var body: some View {
16 | ZStack {
17 | Color.green
18 |
19 | VStack {
20 | Text("This view has no data.")
21 | Text("But it has a child that does.")
22 |
23 | GrandChildView().padding()
24 | }
25 | .foregroundColor(.white)
26 | .padding()
27 | }
28 | }
29 | }
30 |
31 | struct ChildView_Previews: PreviewProvider {
32 | static var previews: some View {
33 | // Preview must have access to the required environment object
34 | // because this view previews its child which uses it
35 | ChildView()
36 | .environmentObject(UserSettings())
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/DataFlow/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/DataFlow/Environment/NestingViews.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NestingViews.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 15/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct NestingViews: View {
12 | // Get access to global environment object
13 | @EnvironmentObject var userSettings: UserSettings
14 |
15 | // for demonstration purposes, the nested views have
16 | // different coloured backgrounds
17 |
18 | var body: some View {
19 | ZStack {
20 | Color.yellow.edgesIgnoringSafeArea(.all)
21 |
22 | VStack {
23 | Text(userSettings.isLoggedIn
24 | ? "User Logged In"
25 | : "User Logged Out")
26 | .padding()
27 | .font(.title)
28 |
29 | // Button toggles value in environment object
30 | Button(action: { userSettings.isLoggedIn.toggle() }) {
31 | Text(userSettings.isLoggedIn ? "Log Out" : "Log In")
32 | .modifier(GrayButtonStyle())
33 | }
34 | .padding()
35 |
36 | Spacer()
37 |
38 | // display first nested view
39 | ChildView()
40 | }
41 | }
42 | }
43 | }
44 |
45 | struct NestingViews_Previews: PreviewProvider {
46 | static var previews: some View {
47 | // Preview must have access to the required environment object
48 | NestingViews()
49 | .environmentObject(UserSettings())
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/DataFlow/Environment/GrandChildView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GrandChildView.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 15/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct GrandChildView: View {
12 | // This grandchild view now gets access to the environment object
13 | // even though its parent does not.
14 |
15 | @EnvironmentObject var userSettings: UserSettings
16 |
17 | var body: some View {
18 | let imageName = userSettings.isLoggedIn
19 | ? "person.crop.square"
20 | : "questionmark.square"
21 |
22 | let buttonText = userSettings.isLoggedIn
23 | ? "Log Out"
24 | : "Log In"
25 |
26 | // because there is more than one statement in the body method
27 | // the return keyword is needed to return the View
28 |
29 | return ZStack {
30 | Color.blue
31 |
32 | VStack {
33 | Image(systemName: imageName).padding()
34 |
35 | // Toggling the environment object value changes
36 | // all the views that use it
37 | Button(action: { userSettings.isLoggedIn.toggle() }) {
38 | Text(buttonText).modifier(GrayButtonStyle())
39 | }
40 | }
41 | .padding()
42 | }
43 | .foregroundColor(.white)
44 | .font(.system(size: 100))
45 | }
46 | }
47 |
48 | struct GrandChildView_Previews: PreviewProvider {
49 | static var previews: some View {
50 | GrandChildView()
51 | .environmentObject(UserSettings())
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/DataFlow/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/DataFlow/Observable 1/ColorSetView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorSetDemo.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 17/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ColorSetView: View {
12 | // Using an ObservedObject for reference-based data (classes)
13 | @StateObject private var colorSet = ColorSet()
14 |
15 | // @State property to control when chooser is displayed
16 | @State private var showChooser = false
17 |
18 | var body: some View {
19 | ZStack {
20 | colorSet.backgroundColor
21 | .edgesIgnoringSafeArea(.all)
22 |
23 | Image(systemName: "ant.fill")
24 | .foregroundColor(colorSet.foregroundColor)
25 | .font(.system(size: 200))
26 |
27 | VStack {
28 | Spacer()
29 |
30 | Button(action: { showChooser = true }) {
31 | Text("Change Colors")
32 | .frame(width: 170, height: 50)
33 | .background(Color.blue)
34 | .foregroundColor(.white)
35 | .cornerRadius(20)
36 | }
37 | }
38 | }
39 | .sheet(isPresented: $showChooser) {
40 | // present the sheet, passing the ObservedObject
41 | // notice that this does not use $ as the ColorChooser
42 | // will get a reference to the ColorSet object
43 | ColorChooser(colorSet: colorSet)
44 |
45 | // changes to this object get passed back automatically
46 | // and used to update this view
47 | }
48 | }
49 | }
50 |
51 | struct ColorSetDemo_Previews: PreviewProvider {
52 | static var previews: some View {
53 | ColorSetView()
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/DataFlow/State & Binding 1/Numbers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Numbers.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 16/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct Numbers: View {
12 | @State private var stepperValue = 0
13 |
14 | var body: some View {
15 | VStack {
16 | Text("Parent view value = \(stepperValue)")
17 | .font(.title)
18 |
19 | NumberChooser(stepperValue: $stepperValue)
20 | }
21 | }
22 | }
23 |
24 | struct Numbers_Previews: PreviewProvider {
25 | static var previews: some View {
26 | Numbers()
27 | }
28 | }
29 |
30 | struct NumberChooser: View {
31 | // Using state from parent with 2-way binding
32 | @Binding var stepperValue: Int
33 |
34 | var body: some View {
35 | ZStack {
36 | RoundedRectangle(cornerRadius: 15)
37 | .fill(Color.init(red: 0.95, green: 0.95, blue: 0.95))
38 | .frame(height: 300)
39 |
40 | VStack {
41 | // Using bound state from parent with 2-way binding
42 | Stepper(value: $stepperValue, in: 0...20) {
43 | Text("Value in child = \(stepperValue)")
44 | }
45 | .padding(50)
46 |
47 | // Using bound state from parent as property
48 | // this view cannot change the value
49 | NumberBlock(stepperValue: stepperValue)
50 | }
51 | }
52 | .padding()
53 | }
54 | }
55 |
56 | struct NumberBlock: View {
57 | // As this view never changes the value, there is no need to bind it
58 | var stepperValue: Int
59 |
60 | var body: some View {
61 | Image(systemName: "\(stepperValue).square")
62 | .font(.system(size: 100))
63 | .foregroundColor(.blue)
64 | .padding(.bottom, 20)
65 | }
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/DataFlow/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/DataFlow/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/DataFlow/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ContentView: View {
12 | @State private var tabSelection = 0
13 |
14 | var body: some View {
15 | NavigationView {
16 | List {
17 | NavigationLink(destination: Property()) {
18 | ListContents(title: "Property", imageNumber: 1)
19 | }
20 |
21 | NavigationLink(destination: UsingState()) {
22 | ListContents(title: "@State", imageNumber: 2)
23 | }
24 |
25 | NavigationLink(destination: Numbers()) {
26 | ListContents(title: "@State & @Binding 1", imageNumber: 3)
27 | }
28 |
29 | NavigationLink(destination: PizzaView()) {
30 | ListContents(title: "@State & @Binding 2", imageNumber: 4)
31 | }
32 |
33 | NavigationLink(destination: ColorSetView()) {
34 | ListContents(title: "ObservableObject 1", imageNumber: 5)
35 | }
36 |
37 | NavigationLink(destination: PersonListView()) {
38 | ListContents(title: "ObservableObject 2", imageNumber: 6)
39 | }
40 |
41 | NavigationLink(destination: NestingViews().environmentObject(UserSettings())) {
42 | ListContents(title: "@EnvironmentObject", imageNumber: 7)
43 | }
44 | }
45 | .navigationBarTitle("Examples")
46 | }
47 | }
48 | }
49 |
50 | struct ContentView_Previews: PreviewProvider {
51 | static var previews: some View {
52 | ContentView()
53 | }
54 | }
55 |
56 | struct ListContents: View {
57 | let title: String
58 | let imageNumber: Int
59 |
60 | var body: some View {
61 | HStack {
62 | Image(systemName: "\(imageNumber).square")
63 | .padding()
64 | .font(.largeTitle)
65 | Text(title)
66 | .font(.headline)
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/DataFlow/Observable 2/PersonDetailView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PersonDetailView.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct PersonDetailView: View {
12 | // Data passed from parent list view
13 | @Binding var person: PersonViewModel
14 |
15 | // SwiftUI form with data fields
16 | // note the autocapitalization and keyboard modifiers
17 |
18 | var body: some View {
19 | VStack {
20 | Form {
21 | Section(header: Text("First Name")) {
22 | TextField("Enter first name", text: $person.first)
23 | }
24 |
25 | Section(header: Text("Last Name")) {
26 | TextField("Enter last name", text: $person.last)
27 | }
28 |
29 | Section(header: Text("Phone Number")) {
30 | TextField("Enter phone number", text: $person.phone)
31 | .keyboardType(.phonePad)
32 | }
33 |
34 | Section(header: Text("Address")) {
35 | TextField("Address", text: $person.address)
36 | TextField("City", text: $person.city)
37 | TextField("State", text: $person.state)
38 | TextField("Zip", text: $person.zip)
39 | }
40 | }
41 | .autocapitalization(.words)
42 |
43 | Text("Registered on:")
44 | .font(.headline)
45 | .padding(6)
46 | Text("\(person.registered, formatter: dateFormatter)")
47 | }
48 | }
49 |
50 | // Formatter for registration date
51 | var dateFormatter: DateFormatter {
52 | let df = DateFormatter()
53 | df.timeStyle = .short
54 | df.dateStyle = .long
55 | return df
56 | }
57 | }
58 |
59 | // Previewing requires using .constant to convert the data to a binding
60 | // Sample data is generated in an extension in Preview Content
61 |
62 | struct PersonDetailView_Previews: PreviewProvider {
63 | static var previews: some View {
64 | let person = PersonViewModel.samplePerson()
65 | return PersonDetailView(person: .constant(person))
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/DataFlow/Observable 1/ColorChooser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorChooser.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 17/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ColorChooser: View {
12 | @ObservedObject var colorSet: ColorSet
13 |
14 | var body: some View {
15 | ZStack {
16 | Color(red: 0.95, green: 0.95, blue: 0.95)
17 | .edgesIgnoringSafeArea(.all)
18 |
19 | VStack {
20 | // The 2 Chooser subviews also get passed the ObservedObject
21 | ForeColorChooser(colorSet: colorSet)
22 |
23 | Divider()
24 |
25 | BackColorChooser(colorSet: colorSet)
26 |
27 | }
28 | }
29 | }
30 | }
31 |
32 | struct ColorChooser_Previews: PreviewProvider {
33 | static var previews: some View {
34 | ColorChooser(colorSet: ColorSet())
35 | }
36 | }
37 |
38 | struct ForeColorChooser: View {
39 | @ObservedObject var colorSet: ColorSet
40 |
41 | var body: some View {
42 | Group {
43 | HStack {
44 | Text("Foreground Red:").frame(width: 150)
45 | Slider(value: $colorSet.foregroundRed, in: 0.0 ... 1.0)
46 | }.padding()
47 |
48 | HStack {
49 | Text("Foreground Green:").frame(width: 150)
50 | Slider(value: $colorSet.foregroundGreen, in: 0.0 ... 1.0)
51 | }.padding()
52 |
53 | HStack {
54 | Text("Foreground Blue:").frame(width: 150)
55 | Slider(value: $colorSet.foregroundBlue, in: 0.0 ... 1.0)
56 | }.padding()
57 |
58 | RoundedRectangle(cornerRadius: 20)
59 | .fill(colorSet.foregroundColor)
60 | .frame(height: 60)
61 | .padding()
62 | }
63 | }
64 | }
65 |
66 | struct BackColorChooser: View {
67 | @ObservedObject var colorSet: ColorSet
68 |
69 | var body: some View {
70 | Group {
71 | HStack {
72 | Text("Background Red:").frame(width: 150)
73 | Slider(value: $colorSet.backgroundRed, in: 0.0 ... 1.0)
74 | }.padding()
75 |
76 | HStack {
77 | Text("Background Green:").frame(width: 150)
78 | Slider(value: $colorSet.backgroundGreen, in: 0.0 ... 1.0)
79 | }.padding()
80 |
81 | HStack {
82 | Text("Background Blue:").frame(width: 150)
83 | Slider(value: $colorSet.backgroundBlue, in: 0.0 ... 1.0)
84 | }.padding()
85 |
86 | RoundedRectangle(cornerRadius: 20)
87 | .fill(colorSet.backgroundColor)
88 | .frame(height: 60)
89 | .padding()
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/DataFlow/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftUI
11 |
12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
21 |
22 | // Create the SwiftUI view that provides the window contents.
23 | let contentView = ContentView()
24 |
25 | // Use a UIHostingController as window root view controller.
26 | if let windowScene = scene as? UIWindowScene {
27 | let window = UIWindow(windowScene: windowScene)
28 | window.rootViewController = UIHostingController(rootView: contentView)
29 | self.window = window
30 | window.makeKeyAndVisible()
31 | }
32 | }
33 |
34 | func sceneDidDisconnect(_ scene: UIScene) {
35 | // Called as the scene is being released by the system.
36 | // This occurs shortly after the scene enters the background, or when its session is discarded.
37 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
38 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
39 | }
40 |
41 | func sceneDidBecomeActive(_ scene: UIScene) {
42 | // Called when the scene has moved from an inactive state to an active state.
43 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
44 | }
45 |
46 | func sceneWillResignActive(_ scene: UIScene) {
47 | // Called when the scene will move from an active state to an inactive state.
48 | // This may occur due to temporary interruptions (ex. an incoming phone call).
49 | }
50 |
51 | func sceneWillEnterForeground(_ scene: UIScene) {
52 | // Called as the scene transitions from the background to the foreground.
53 | // Use this method to undo the changes made on entering the background.
54 | }
55 |
56 | func sceneDidEnterBackground(_ scene: UIScene) {
57 | // Called as the scene transitions from the foreground to the background.
58 | // Use this method to save data, release shared resources, and store enough scene-specific state information
59 | // to restore the scene back to its current state.
60 | }
61 |
62 |
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/DataFlow/State & Binding 2/PizzaView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PizzaView.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct PizzaView: View {
12 | // Using @State for a struct
13 | @State private var pizza = Pizza()
14 |
15 | var body: some View {
16 | VStack {
17 | Form {
18 | // Using 2-way binding but each component
19 | // only needs 1 property from the struct
20 | PizzaNamePicker(selectedPizzaName: $pizza.name)
21 | PizzaSizePicker(selectedPizzaSize: $pizza.size)
22 | PizzaCrustPicker(selectedPizzaCrust: $pizza.crust)
23 | }
24 |
25 | // Text representation to prove that the
26 | // subviews are modifying the parent struct
27 | Text(pizza.pizzaSelection)
28 | .padding()
29 | .multilineTextAlignment(.center)
30 | }
31 | .navigationBarTitle("Choose Your Pizza")
32 | }
33 | }
34 |
35 | struct PizzaView_Previews: PreviewProvider {
36 | static var previews: some View {
37 | PizzaView()
38 | }
39 | }
40 |
41 | struct PizzaNamePicker: View {
42 | @Binding var selectedPizzaName: PizzaName
43 |
44 | var body: some View {
45 | Section(header: Text("Select your pizza:").font(.headline)) {
46 | List(PizzaName.allCases, id: \.self) { pizzaName in
47 | Button(action: { selectedPizzaName = pizzaName }) {
48 | PizzaNamePickerRow(selectedPizzaName: selectedPizzaName,
49 | pizzaName: pizzaName)
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
56 | struct PizzaNamePickerRow: View {
57 | // sub-subview for the pizza name row
58 | // still using 2-way binding for the selected pizza name
59 | // and gets a property for the name to display
60 |
61 | let selectedPizzaName: PizzaName
62 | let pizzaName: PizzaName
63 |
64 | var body: some View {
65 | HStack {
66 | Text(pizzaName.rawValue.capitalized)
67 | Spacer()
68 | if pizzaName == selectedPizzaName {
69 | Image(systemName: "checkmark")
70 | }
71 | }
72 | .foregroundColor(.primary)
73 | }
74 | }
75 |
76 | struct PizzaSizePicker: View {
77 | @Binding var selectedPizzaSize: PizzaSize
78 |
79 | var body: some View {
80 | Section(header: Text("Select your size:").font(.headline)) {
81 | Picker(selection: $selectedPizzaSize, label: Text("Pizza Size")) {
82 | ForEach(PizzaSize.allCases, id: \.self) { pizzaSize in
83 | Text(pizzaSize.rawValue.capitalized).tag(pizzaSize)
84 | }
85 | }
86 | .pickerStyle(SegmentedPickerStyle())
87 | }
88 | }
89 | }
90 |
91 | struct PizzaCrustPicker: View {
92 | @Binding var selectedPizzaCrust: PizzaCrust
93 |
94 | var body: some View {
95 | Section(header: Text("Select your crust:").font(.headline)) {
96 | Picker(selection: $selectedPizzaCrust, label: Text("Pizza Crust")) {
97 | ForEach(PizzaCrust.allCases, id: \.self) { pizzaCrust in
98 | Text(pizzaCrust.rawValue.capitalized).tag(pizzaCrust)
99 | }
100 | }
101 | .pickerStyle(SegmentedPickerStyle())
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/DataFlow/Observable 2/PersonListView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PersonList.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct PersonListView: View {
12 | // Using an ObservedObject for reference-based data (classes)
13 | @StateObject var personList = PersonListModel()
14 |
15 | var body: some View {
16 | List {
17 | // To make the navigation link edits return to here,
18 | // the data sent must be a direct reference to an element
19 | // of the ObservedObject, not the closure parameter.
20 |
21 | // Thanks to Stewart Lynch (@StewartLynch) for suggesting using a function to
22 | // get a binding to the person so it coud be passed to the detail view.
23 |
24 | // And now thanks to Vadim Shpakovski (@vadimshpakovski) for another option
25 | // which does not rely on creating a binding to every person, but uses
26 | // onReceive to react to changes to the person and trigger an update of personList.
27 | // This will be faster for longer lists and feels more like how ObservedObject is meant to be used.
28 | // Note that PersonDetailView has changed from using @Binding to @ObservedObject.
29 |
30 | // And a further update after receiving some more feedback which suggested
31 | // that using @Binding was better as it means that the entire ForEach doid not have to be
32 | // re-calcaulted afetr every change. But this uses a Dictionary to avoid Stewart's function.
33 |
34 | ForEach(personList.ids, id: \.self) { id in
35 | NavigationLink(
36 | destination: PersonDetailView(person: $personList.persons[unchecked: id])
37 | ) {
38 | Text("\(personList.persons[unchecked: id].first)") +
39 | Text(" \(personList.persons[unchecked: id].last)")
40 | }
41 | }
42 | .onDelete { indexSet in
43 | // add this modifier to allow deleting from the list
44 | personList.ids.remove(atOffsets: indexSet)
45 | }
46 | .onMove { indices, newOffset in
47 | // add this modifier to allow moving in the list
48 | personList.ids.move(fromOffsets: indices, toOffset: newOffset)
49 | }
50 | }
51 |
52 | // This runs when the view appears to load the initial data
53 | .onAppear(perform: { personList.fetchData() })
54 |
55 | // set up the navigation bar details
56 | // EditButton() is a standard View
57 | .navigationBarTitle("People")
58 | .navigationBarItems(trailing:
59 | HStack {
60 | Button(action: { personList.refreshData() }) {
61 | Image(systemName: "arrow.clockwise")
62 | }
63 | Spacer().frame(width: 30)
64 | EditButton()
65 | }
66 | )
67 | }
68 |
69 | }
70 |
71 | // To preview this with navigation, it must be embedded in a NavigationView
72 | // but the main ContentView provides the main NavigationView
73 | // so this view will only get its own when in Proview mode
74 |
75 | struct PersonList_Previews: PreviewProvider {
76 | static var previews: some View {
77 | NavigationView {
78 | PersonListView()
79 | }
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/DataFlow/Observable 2/PersonListModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PersonsModel.swift
3 | // DataFlow
4 | //
5 | // Created by Sarah Reichelt on 14/09/2019.
6 | // Copyright © 2019 TrozWare. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class PersonListModel: ObservableObject {
12 | // Main list view model
13 | // ObservableObject so that updates are detected
14 |
15 | @Published var ids: [UUID] = []
16 | @Published var persons: [UUID : PersonViewModel] = [:]
17 |
18 | func fetchData() {
19 | // avoid too many calls to the API
20 | if ids.count > 0 { return }
21 |
22 | let address = "https://next.json-generator.com/api/json/get/VyQroKB8P?indent=2"
23 | guard let url = URL(string: address) else {
24 | fatalError("Bad data URL!")
25 | }
26 |
27 | URLSession.shared.dataTask(with: url) { (data, response, error) in
28 | guard let data = data, error == nil else {
29 | print("Error fetching data")
30 | return
31 | }
32 |
33 | do {
34 | let jsonDecoder = JSONDecoder()
35 | jsonDecoder.dateDecodingStrategy = .iso8601
36 | let dataArray = try jsonDecoder.decode([PersonModel].self, from: data)
37 | DispatchQueue.main.async {
38 | let personViewModels = dataArray.map { PersonViewModel(with: $0) }.sorted() {
39 | $0.last + $0.first < $1.last + $1.first
40 | }
41 | self.ids = personViewModels.map { $0.id }
42 | self.persons = Dictionary(
43 | uniqueKeysWithValues: personViewModels.map { ($0.id, $0) }
44 | )
45 | }
46 | } catch {
47 | print(error)
48 | }
49 | }.resume()
50 | }
51 |
52 | func refreshData() {
53 | ids = []
54 | persons = [:]
55 | fetchData()
56 | }
57 | }
58 |
59 | class PersonViewModel: Identifiable, ObservableObject {
60 |
61 | // Main model for use as ObservableObject
62 | // Derived from JSON via basic model
63 |
64 | // Even though this is not observed directly,
65 | // it must be an ObservableObject for the data flow to work
66 |
67 | var id = UUID()
68 | var first: String = ""
69 | var last: String = ""
70 | var phone: String = ""
71 | var address: String = ""
72 | var city: String = ""
73 | var state: String = ""
74 | var zip: String = ""
75 | var registered: Date = Date()
76 |
77 | init(with person: PersonModel) {
78 | self.id = person.id
79 | self.first = person.first
80 | self.last = person.last
81 | self.phone = person.phone
82 | self.address = person.address
83 | self.city = person.city
84 | self.state = person.state
85 | self.zip = person.zip
86 | self.registered = person.registered
87 | }
88 |
89 | init() { }
90 |
91 | }
92 |
93 | struct PersonModel: Codable {
94 | // Basic model for decoding from JSON
95 |
96 | let id: UUID
97 | let first: String
98 | let last: String
99 | let phone: String
100 | let address: String
101 | let city: String
102 | let state: String
103 | let zip: String
104 | let registered: Date
105 |
106 | init(from decoder: Decoder) throws {
107 | let values = try decoder.container(keyedBy: CodingKeys.self)
108 | id = try values.decode(UUID.self, forKey: .id)
109 | first = try values.decode(String.self, forKey: .first)
110 | last = try values.decode(String.self, forKey: .last)
111 | phone = try values.decode(String.self, forKey: .phone)
112 | registered = try values.decode(Date.self, forKey: .registered)
113 |
114 | // split up address into separate lines for easier editing
115 | let addressData = try values.decode(String.self, forKey: .address)
116 | let addressComponents = addressData.components(separatedBy: ", ")
117 | address = addressComponents[0]
118 | city = addressComponents[1]
119 | state = addressComponents[2]
120 | zip = addressComponents[3]
121 | }
122 | }
123 |
124 | // Extension to force un-wrap a Dictionary value which is normally an optional.
125 | // This is so it can be used to create a Binding.
126 | extension Dictionary where Key == UUID, Value == PersonViewModel {
127 | subscript(unchecked key: Key) -> Value {
128 | get {
129 | guard let result = self[key] else {
130 | fatalError("This person does not exist.")
131 | }
132 | return result
133 | }
134 | set {
135 | self[key] = newValue
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/DataFlow.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2628DB08232DE93000049FFD /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2628DB07232DE93000049FFD /* UserSettings.swift */; };
11 | 2628DB0A232DE94D00049FFD /* CustomModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2628DB09232DE94D00049FFD /* CustomModifiers.swift */; };
12 | 263DF0AD232C7F3E007635A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263DF0AC232C7F3E007635A4 /* AppDelegate.swift */; };
13 | 263DF0AF232C7F3E007635A4 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263DF0AE232C7F3E007635A4 /* SceneDelegate.swift */; };
14 | 263DF0B1232C7F3E007635A4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263DF0B0232C7F3E007635A4 /* ContentView.swift */; };
15 | 263DF0B3232C7F41007635A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 263DF0B2232C7F41007635A4 /* Assets.xcassets */; };
16 | 263DF0B6232C7F41007635A4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 263DF0B5232C7F41007635A4 /* Preview Assets.xcassets */; };
17 | 263DF0B9232C7F41007635A4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 263DF0B7232C7F41007635A4 /* LaunchScreen.storyboard */; };
18 | 263DF0C1232C991E007635A4 /* PizzaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263DF0C0232C991E007635A4 /* PizzaView.swift */; };
19 | 263DF0C3232C994B007635A4 /* Pizza.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263DF0C2232C994B007635A4 /* Pizza.swift */; };
20 | 264663C2232EFC4200368113 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264663C1232EFC4200368113 /* Property.swift */; };
21 | 264663C4232EFD5300368113 /* UsingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264663C3232EFD5300368113 /* UsingState.swift */; };
22 | 264663C7232EFF3B00368113 /* Numbers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264663C6232EFF3B00368113 /* Numbers.swift */; };
23 | 264C426D232CD3EE00058CE0 /* PersonListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264C426C232CD3EE00058CE0 /* PersonListModel.swift */; };
24 | 264C426F232CD57D00058CE0 /* PersonListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264C426E232CD57D00058CE0 /* PersonListView.swift */; };
25 | 264C4271232CD87900058CE0 /* PersonDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 264C4270232CD87900058CE0 /* PersonDetailView.swift */; };
26 | 26834F892337544E0013D5DD /* PersonVMTestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26834F882337544E0013D5DD /* PersonVMTestData.swift */; };
27 | 26BDC7DD232DD34200C0A2D9 /* NestingViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BDC7DC232DD34200C0A2D9 /* NestingViews.swift */; };
28 | 26BDC7DF232DE63900C0A2D9 /* ChildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BDC7DE232DE63900C0A2D9 /* ChildView.swift */; };
29 | 26BDC7E1232DE6CE00C0A2D9 /* GrandChildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BDC7E0232DE6CE00C0A2D9 /* GrandChildView.swift */; };
30 | 26E47A642330988800186B82 /* ColorSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E47A632330988800186B82 /* ColorSet.swift */; };
31 | 26E47A6623309A0E00186B82 /* ColorSetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E47A6523309A0E00186B82 /* ColorSetView.swift */; };
32 | 26E47A6823309BDB00186B82 /* ColorChooser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E47A6723309BDB00186B82 /* ColorChooser.swift */; };
33 | /* End PBXBuildFile section */
34 |
35 | /* Begin PBXFileReference section */
36 | 2628DB07232DE93000049FFD /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = ""; };
37 | 2628DB09232DE94D00049FFD /* CustomModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomModifiers.swift; sourceTree = ""; };
38 | 263DF0A9232C7F3E007635A4 /* DataFlow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DataFlow.app; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 263DF0AC232C7F3E007635A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
40 | 263DF0AE232C7F3E007635A4 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
41 | 263DF0B0232C7F3E007635A4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
42 | 263DF0B2232C7F41007635A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 263DF0B5232C7F41007635A4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
44 | 263DF0B8232C7F41007635A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
45 | 263DF0BA232C7F41007635A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
46 | 263DF0C0232C991E007635A4 /* PizzaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PizzaView.swift; sourceTree = ""; };
47 | 263DF0C2232C994B007635A4 /* Pizza.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pizza.swift; sourceTree = ""; };
48 | 264663C1232EFC4200368113 /* Property.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; };
49 | 264663C3232EFD5300368113 /* UsingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsingState.swift; sourceTree = ""; };
50 | 264663C6232EFF3B00368113 /* Numbers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Numbers.swift; sourceTree = ""; };
51 | 264C426C232CD3EE00058CE0 /* PersonListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonListModel.swift; sourceTree = ""; };
52 | 264C426E232CD57D00058CE0 /* PersonListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonListView.swift; sourceTree = ""; };
53 | 264C4270232CD87900058CE0 /* PersonDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonDetailView.swift; sourceTree = ""; };
54 | 26834F882337544E0013D5DD /* PersonVMTestData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonVMTestData.swift; sourceTree = ""; };
55 | 26BDC7DC232DD34200C0A2D9 /* NestingViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestingViews.swift; sourceTree = ""; };
56 | 26BDC7DE232DE63900C0A2D9 /* ChildView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChildView.swift; sourceTree = ""; };
57 | 26BDC7E0232DE6CE00C0A2D9 /* GrandChildView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrandChildView.swift; sourceTree = ""; };
58 | 26E47A632330988800186B82 /* ColorSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSet.swift; sourceTree = ""; };
59 | 26E47A6523309A0E00186B82 /* ColorSetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSetView.swift; sourceTree = ""; };
60 | 26E47A6723309BDB00186B82 /* ColorChooser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorChooser.swift; sourceTree = ""; };
61 | /* End PBXFileReference section */
62 |
63 | /* Begin PBXFrameworksBuildPhase section */
64 | 263DF0A6232C7F3E007635A4 /* Frameworks */ = {
65 | isa = PBXFrameworksBuildPhase;
66 | buildActionMask = 2147483647;
67 | files = (
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | /* End PBXFrameworksBuildPhase section */
72 |
73 | /* Begin PBXGroup section */
74 | 263DF0A0232C7F3E007635A4 = {
75 | isa = PBXGroup;
76 | children = (
77 | 263DF0AB232C7F3E007635A4 /* DataFlow */,
78 | 263DF0AA232C7F3E007635A4 /* Products */,
79 | );
80 | sourceTree = "";
81 | };
82 | 263DF0AA232C7F3E007635A4 /* Products */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 263DF0A9232C7F3E007635A4 /* DataFlow.app */,
86 | );
87 | name = Products;
88 | sourceTree = "";
89 | };
90 | 263DF0AB232C7F3E007635A4 /* DataFlow */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 263DF0AC232C7F3E007635A4 /* AppDelegate.swift */,
94 | 263DF0AE232C7F3E007635A4 /* SceneDelegate.swift */,
95 | 263DF0B0232C7F3E007635A4 /* ContentView.swift */,
96 | 264663C1232EFC4200368113 /* Property.swift */,
97 | 264663C3232EFD5300368113 /* UsingState.swift */,
98 | 264663C5232EFF2300368113 /* State & Binding 1 */,
99 | 26BDC7D9232DB93900C0A2D9 /* State & Binding 2 */,
100 | 26E47A622330986700186B82 /* Observable 1 */,
101 | 26BDC7DA232DB94C00C0A2D9 /* Observable 2 */,
102 | 26BDC7DB232DD32E00C0A2D9 /* Environment */,
103 | 263DF0B2232C7F41007635A4 /* Assets.xcassets */,
104 | 263DF0B7232C7F41007635A4 /* LaunchScreen.storyboard */,
105 | 263DF0BA232C7F41007635A4 /* Info.plist */,
106 | 263DF0B4232C7F41007635A4 /* Preview Content */,
107 | );
108 | path = DataFlow;
109 | sourceTree = "";
110 | };
111 | 263DF0B4232C7F41007635A4 /* Preview Content */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 263DF0B5232C7F41007635A4 /* Preview Assets.xcassets */,
115 | 26834F882337544E0013D5DD /* PersonVMTestData.swift */,
116 | );
117 | path = "Preview Content";
118 | sourceTree = "";
119 | };
120 | 264663C5232EFF2300368113 /* State & Binding 1 */ = {
121 | isa = PBXGroup;
122 | children = (
123 | 264663C6232EFF3B00368113 /* Numbers.swift */,
124 | );
125 | path = "State & Binding 1";
126 | sourceTree = "";
127 | };
128 | 26BDC7D9232DB93900C0A2D9 /* State & Binding 2 */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 263DF0C0232C991E007635A4 /* PizzaView.swift */,
132 | 263DF0C2232C994B007635A4 /* Pizza.swift */,
133 | );
134 | path = "State & Binding 2";
135 | sourceTree = "";
136 | };
137 | 26BDC7DA232DB94C00C0A2D9 /* Observable 2 */ = {
138 | isa = PBXGroup;
139 | children = (
140 | 264C426E232CD57D00058CE0 /* PersonListView.swift */,
141 | 264C4270232CD87900058CE0 /* PersonDetailView.swift */,
142 | 264C426C232CD3EE00058CE0 /* PersonListModel.swift */,
143 | );
144 | path = "Observable 2";
145 | sourceTree = "";
146 | };
147 | 26BDC7DB232DD32E00C0A2D9 /* Environment */ = {
148 | isa = PBXGroup;
149 | children = (
150 | 26BDC7DC232DD34200C0A2D9 /* NestingViews.swift */,
151 | 26BDC7DE232DE63900C0A2D9 /* ChildView.swift */,
152 | 26BDC7E0232DE6CE00C0A2D9 /* GrandChildView.swift */,
153 | 2628DB07232DE93000049FFD /* UserSettings.swift */,
154 | 2628DB09232DE94D00049FFD /* CustomModifiers.swift */,
155 | );
156 | path = Environment;
157 | sourceTree = "";
158 | };
159 | 26E47A622330986700186B82 /* Observable 1 */ = {
160 | isa = PBXGroup;
161 | children = (
162 | 26E47A6523309A0E00186B82 /* ColorSetView.swift */,
163 | 26E47A6723309BDB00186B82 /* ColorChooser.swift */,
164 | 26E47A632330988800186B82 /* ColorSet.swift */,
165 | );
166 | path = "Observable 1";
167 | sourceTree = "";
168 | };
169 | /* End PBXGroup section */
170 |
171 | /* Begin PBXNativeTarget section */
172 | 263DF0A8232C7F3E007635A4 /* DataFlow */ = {
173 | isa = PBXNativeTarget;
174 | buildConfigurationList = 263DF0BD232C7F41007635A4 /* Build configuration list for PBXNativeTarget "DataFlow" */;
175 | buildPhases = (
176 | 263DF0A5232C7F3E007635A4 /* Sources */,
177 | 263DF0A6232C7F3E007635A4 /* Frameworks */,
178 | 263DF0A7232C7F3E007635A4 /* Resources */,
179 | );
180 | buildRules = (
181 | );
182 | dependencies = (
183 | );
184 | name = DataFlow;
185 | productName = DataFlow;
186 | productReference = 263DF0A9232C7F3E007635A4 /* DataFlow.app */;
187 | productType = "com.apple.product-type.application";
188 | };
189 | /* End PBXNativeTarget section */
190 |
191 | /* Begin PBXProject section */
192 | 263DF0A1232C7F3E007635A4 /* Project object */ = {
193 | isa = PBXProject;
194 | attributes = {
195 | LastSwiftUpdateCheck = 1100;
196 | LastUpgradeCheck = 1240;
197 | ORGANIZATIONNAME = TrozWare;
198 | TargetAttributes = {
199 | 263DF0A8232C7F3E007635A4 = {
200 | CreatedOnToolsVersion = 11.0;
201 | };
202 | };
203 | };
204 | buildConfigurationList = 263DF0A4232C7F3E007635A4 /* Build configuration list for PBXProject "DataFlow" */;
205 | compatibilityVersion = "Xcode 9.3";
206 | developmentRegion = en;
207 | hasScannedForEncodings = 0;
208 | knownRegions = (
209 | en,
210 | Base,
211 | );
212 | mainGroup = 263DF0A0232C7F3E007635A4;
213 | productRefGroup = 263DF0AA232C7F3E007635A4 /* Products */;
214 | projectDirPath = "";
215 | projectRoot = "";
216 | targets = (
217 | 263DF0A8232C7F3E007635A4 /* DataFlow */,
218 | );
219 | };
220 | /* End PBXProject section */
221 |
222 | /* Begin PBXResourcesBuildPhase section */
223 | 263DF0A7232C7F3E007635A4 /* Resources */ = {
224 | isa = PBXResourcesBuildPhase;
225 | buildActionMask = 2147483647;
226 | files = (
227 | 263DF0B9232C7F41007635A4 /* LaunchScreen.storyboard in Resources */,
228 | 263DF0B6232C7F41007635A4 /* Preview Assets.xcassets in Resources */,
229 | 263DF0B3232C7F41007635A4 /* Assets.xcassets in Resources */,
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | /* End PBXResourcesBuildPhase section */
234 |
235 | /* Begin PBXSourcesBuildPhase section */
236 | 263DF0A5232C7F3E007635A4 /* Sources */ = {
237 | isa = PBXSourcesBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | 264663C2232EFC4200368113 /* Property.swift in Sources */,
241 | 264C426D232CD3EE00058CE0 /* PersonListModel.swift in Sources */,
242 | 26E47A6823309BDB00186B82 /* ColorChooser.swift in Sources */,
243 | 2628DB08232DE93000049FFD /* UserSettings.swift in Sources */,
244 | 26E47A642330988800186B82 /* ColorSet.swift in Sources */,
245 | 26BDC7DD232DD34200C0A2D9 /* NestingViews.swift in Sources */,
246 | 264663C7232EFF3B00368113 /* Numbers.swift in Sources */,
247 | 264663C4232EFD5300368113 /* UsingState.swift in Sources */,
248 | 26BDC7E1232DE6CE00C0A2D9 /* GrandChildView.swift in Sources */,
249 | 263DF0AD232C7F3E007635A4 /* AppDelegate.swift in Sources */,
250 | 264C426F232CD57D00058CE0 /* PersonListView.swift in Sources */,
251 | 263DF0AF232C7F3E007635A4 /* SceneDelegate.swift in Sources */,
252 | 263DF0B1232C7F3E007635A4 /* ContentView.swift in Sources */,
253 | 26834F892337544E0013D5DD /* PersonVMTestData.swift in Sources */,
254 | 2628DB0A232DE94D00049FFD /* CustomModifiers.swift in Sources */,
255 | 263DF0C3232C994B007635A4 /* Pizza.swift in Sources */,
256 | 264C4271232CD87900058CE0 /* PersonDetailView.swift in Sources */,
257 | 26E47A6623309A0E00186B82 /* ColorSetView.swift in Sources */,
258 | 263DF0C1232C991E007635A4 /* PizzaView.swift in Sources */,
259 | 26BDC7DF232DE63900C0A2D9 /* ChildView.swift in Sources */,
260 | );
261 | runOnlyForDeploymentPostprocessing = 0;
262 | };
263 | /* End PBXSourcesBuildPhase section */
264 |
265 | /* Begin PBXVariantGroup section */
266 | 263DF0B7232C7F41007635A4 /* LaunchScreen.storyboard */ = {
267 | isa = PBXVariantGroup;
268 | children = (
269 | 263DF0B8232C7F41007635A4 /* Base */,
270 | );
271 | name = LaunchScreen.storyboard;
272 | sourceTree = "";
273 | };
274 | /* End PBXVariantGroup section */
275 |
276 | /* Begin XCBuildConfiguration section */
277 | 263DF0BB232C7F41007635A4 /* Debug */ = {
278 | isa = XCBuildConfiguration;
279 | buildSettings = {
280 | ALWAYS_SEARCH_USER_PATHS = NO;
281 | CLANG_ANALYZER_NONNULL = YES;
282 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
283 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
284 | CLANG_CXX_LIBRARY = "libc++";
285 | CLANG_ENABLE_MODULES = YES;
286 | CLANG_ENABLE_OBJC_ARC = YES;
287 | CLANG_ENABLE_OBJC_WEAK = YES;
288 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
289 | CLANG_WARN_BOOL_CONVERSION = YES;
290 | CLANG_WARN_COMMA = YES;
291 | CLANG_WARN_CONSTANT_CONVERSION = YES;
292 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
293 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
294 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
295 | CLANG_WARN_EMPTY_BODY = YES;
296 | CLANG_WARN_ENUM_CONVERSION = YES;
297 | CLANG_WARN_INFINITE_RECURSION = YES;
298 | CLANG_WARN_INT_CONVERSION = YES;
299 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
300 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
301 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
302 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
303 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
304 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
305 | CLANG_WARN_STRICT_PROTOTYPES = YES;
306 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
307 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
308 | CLANG_WARN_UNREACHABLE_CODE = YES;
309 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
310 | COPY_PHASE_STRIP = NO;
311 | DEBUG_INFORMATION_FORMAT = dwarf;
312 | ENABLE_STRICT_OBJC_MSGSEND = YES;
313 | ENABLE_TESTABILITY = YES;
314 | GCC_C_LANGUAGE_STANDARD = gnu11;
315 | GCC_DYNAMIC_NO_PIC = NO;
316 | GCC_NO_COMMON_BLOCKS = YES;
317 | GCC_OPTIMIZATION_LEVEL = 0;
318 | GCC_PREPROCESSOR_DEFINITIONS = (
319 | "DEBUG=1",
320 | "$(inherited)",
321 | );
322 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
323 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
324 | GCC_WARN_UNDECLARED_SELECTOR = YES;
325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
326 | GCC_WARN_UNUSED_FUNCTION = YES;
327 | GCC_WARN_UNUSED_VARIABLE = YES;
328 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
329 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
330 | MTL_FAST_MATH = YES;
331 | ONLY_ACTIVE_ARCH = YES;
332 | SDKROOT = iphoneos;
333 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
334 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
335 | };
336 | name = Debug;
337 | };
338 | 263DF0BC232C7F41007635A4 /* Release */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | ALWAYS_SEARCH_USER_PATHS = NO;
342 | CLANG_ANALYZER_NONNULL = YES;
343 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
344 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
345 | CLANG_CXX_LIBRARY = "libc++";
346 | CLANG_ENABLE_MODULES = YES;
347 | CLANG_ENABLE_OBJC_ARC = YES;
348 | CLANG_ENABLE_OBJC_WEAK = YES;
349 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
350 | CLANG_WARN_BOOL_CONVERSION = YES;
351 | CLANG_WARN_COMMA = YES;
352 | CLANG_WARN_CONSTANT_CONVERSION = YES;
353 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
354 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
355 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
356 | CLANG_WARN_EMPTY_BODY = YES;
357 | CLANG_WARN_ENUM_CONVERSION = YES;
358 | CLANG_WARN_INFINITE_RECURSION = YES;
359 | CLANG_WARN_INT_CONVERSION = YES;
360 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
361 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
362 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
363 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
364 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
365 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
366 | CLANG_WARN_STRICT_PROTOTYPES = YES;
367 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
368 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
369 | CLANG_WARN_UNREACHABLE_CODE = YES;
370 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
371 | COPY_PHASE_STRIP = NO;
372 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
373 | ENABLE_NS_ASSERTIONS = NO;
374 | ENABLE_STRICT_OBJC_MSGSEND = YES;
375 | GCC_C_LANGUAGE_STANDARD = gnu11;
376 | GCC_NO_COMMON_BLOCKS = YES;
377 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
378 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
379 | GCC_WARN_UNDECLARED_SELECTOR = YES;
380 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
381 | GCC_WARN_UNUSED_FUNCTION = YES;
382 | GCC_WARN_UNUSED_VARIABLE = YES;
383 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
384 | MTL_ENABLE_DEBUG_INFO = NO;
385 | MTL_FAST_MATH = YES;
386 | SDKROOT = iphoneos;
387 | SWIFT_COMPILATION_MODE = wholemodule;
388 | SWIFT_OPTIMIZATION_LEVEL = "-O";
389 | VALIDATE_PRODUCT = YES;
390 | };
391 | name = Release;
392 | };
393 | 263DF0BE232C7F41007635A4 /* Debug */ = {
394 | isa = XCBuildConfiguration;
395 | buildSettings = {
396 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
397 | CODE_SIGN_STYLE = Automatic;
398 | CURRENT_PROJECT_VERSION = 2;
399 | DEVELOPMENT_ASSET_PATHS = "\"DataFlow/Preview Content\"";
400 | DEVELOPMENT_TEAM = TC28MCLCFA;
401 | ENABLE_PREVIEWS = YES;
402 | INFOPLIST_FILE = DataFlow/Info.plist;
403 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
404 | LD_RUNPATH_SEARCH_PATHS = (
405 | "$(inherited)",
406 | "@executable_path/Frameworks",
407 | );
408 | PRODUCT_BUNDLE_IDENTIFIER = net.troz.DataFlow;
409 | PRODUCT_NAME = "$(TARGET_NAME)";
410 | SWIFT_VERSION = 5.0;
411 | TARGETED_DEVICE_FAMILY = "1,2";
412 | };
413 | name = Debug;
414 | };
415 | 263DF0BF232C7F41007635A4 /* Release */ = {
416 | isa = XCBuildConfiguration;
417 | buildSettings = {
418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
419 | CODE_SIGN_STYLE = Automatic;
420 | CURRENT_PROJECT_VERSION = 2;
421 | DEVELOPMENT_ASSET_PATHS = "\"DataFlow/Preview Content\"";
422 | DEVELOPMENT_TEAM = TC28MCLCFA;
423 | ENABLE_PREVIEWS = YES;
424 | INFOPLIST_FILE = DataFlow/Info.plist;
425 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
426 | LD_RUNPATH_SEARCH_PATHS = (
427 | "$(inherited)",
428 | "@executable_path/Frameworks",
429 | );
430 | PRODUCT_BUNDLE_IDENTIFIER = net.troz.DataFlow;
431 | PRODUCT_NAME = "$(TARGET_NAME)";
432 | SWIFT_VERSION = 5.0;
433 | TARGETED_DEVICE_FAMILY = "1,2";
434 | };
435 | name = Release;
436 | };
437 | /* End XCBuildConfiguration section */
438 |
439 | /* Begin XCConfigurationList section */
440 | 263DF0A4232C7F3E007635A4 /* Build configuration list for PBXProject "DataFlow" */ = {
441 | isa = XCConfigurationList;
442 | buildConfigurations = (
443 | 263DF0BB232C7F41007635A4 /* Debug */,
444 | 263DF0BC232C7F41007635A4 /* Release */,
445 | );
446 | defaultConfigurationIsVisible = 0;
447 | defaultConfigurationName = Release;
448 | };
449 | 263DF0BD232C7F41007635A4 /* Build configuration list for PBXNativeTarget "DataFlow" */ = {
450 | isa = XCConfigurationList;
451 | buildConfigurations = (
452 | 263DF0BE232C7F41007635A4 /* Debug */,
453 | 263DF0BF232C7F41007635A4 /* Release */,
454 | );
455 | defaultConfigurationIsVisible = 0;
456 | defaultConfigurationName = Release;
457 | };
458 | /* End XCConfigurationList section */
459 | };
460 | rootObject = 263DF0A1232C7F3E007635A4 /* Project object */;
461 | }
462 |
--------------------------------------------------------------------------------