├── .gitignore
├── README.md
├── SwiftUIPropertyWrapperTalk
├── Assets.xcassets
│ ├── Contents.json
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── ContentView.swift
├── SwiftUIPropertyWrapperTalkApp.swift
├── StringSample.swift
├── Post.swift
└── RemoteData.swift
├── SwiftUI_Property_Wrappers_2022.pdf
├── SwiftUIPropertyWrapperTalk.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── donnywals.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
└── SwiftUIPropertyWrapperTalkTests
└── SwiftUIPropertyWrapperTalkTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | /DS_Store
2 | xcuserdata
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hey!
2 |
3 | This repo is just a small sample to go along with my talk on property wrappers in SwiftUI.
4 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SwiftUI_Property_Wrappers_2022.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnywals/SwiftUIPropertyWrapperTalk/HEAD/SwiftUI_Property_Wrappers_2022.pdf
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // SwiftUIPropertyWrapperTalk
4 | //
5 | // Created by Donny Wals on 14/06/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct PostsView: View {
11 | @RemoteData(endpoint: .feed) var feed: [Post]
12 |
13 | var body: some View {
14 | List(feed) { post in
15 | Text(post.title)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/SwiftUIPropertyWrapperTalkApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIPropertyWrapperTalkApp.swift
3 | // SwiftUIPropertyWrapperTalk
4 | //
5 | // Created by Donny Wals on 14/06/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct SwiftUIPropertyWrapperTalkApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | PostsView()
15 | .environment(\.urlSession, URLSession.shared)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk.xcodeproj/xcuserdata/donnywals.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwiftUIPropertyWrapperTalk.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/StringSample.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringSample.swift
3 | // SwiftUIPropertyWrapperTalk
4 | //
5 | // Created by Donny Wals on 14/06/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | @propertyWrapper
11 | struct StringSample {
12 | let wrappedValue: String
13 |
14 | var projectedValue: String {
15 | "Projected: \(wrappedValue)"
16 | }
17 | }
18 |
19 | struct SampleUsage {
20 | @StringSample var example = "Hello, world"
21 |
22 | func printSample() {
23 | print(example) // "Hello, world"
24 | print(_example) // StringSample
25 | print($example) // "Projected: Hello, world"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/Post.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Post.swift
3 | // SwiftUIPropertyWrapperTalk
4 | //
5 | // Created by Donny Wals on 14/06/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct Post: Codable, Identifiable, Hashable, Equatable {
11 | public let id: Int
12 | public let title: String
13 |
14 | public init(from decoder: Decoder) throws {
15 | let container = try decoder.container(keyedBy: CodingKeys.self)
16 | self.id = try container.decode(Int.self, forKey: .id)
17 |
18 | let titleContainer = try container.nestedContainer(keyedBy: TitleCodingKeys.self, forKey: .title)
19 | self.title = try titleContainer.decode(String.self, forKey: .rendered)
20 | }
21 | }
22 |
23 | extension Post {
24 | enum CodingKeys: CodingKey {
25 | case id
26 | case title
27 | }
28 |
29 | enum TitleCodingKeys: CodingKey {
30 | case rendered
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "2x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "83.5x83.5"
82 | },
83 | {
84 | "idiom" : "ios-marketing",
85 | "scale" : "1x",
86 | "size" : "1024x1024"
87 | }
88 | ],
89 | "info" : {
90 | "author" : "xcode",
91 | "version" : 1
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalkTests/SwiftUIPropertyWrapperTalkTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIPropertyWrapperTalkTests.swift
3 | // SwiftUIPropertyWrapperTalkTests
4 | //
5 | // Created by Donny Wals on 15/06/2022.
6 | //
7 |
8 | import XCTest
9 | import SwiftUI
10 | import Combine
11 | @testable import SwiftUIPropertyWrapperTalk
12 |
13 | class CustomWrapperTest: XCTestCase {
14 | let app = UIViewController()
15 |
16 | final func host(_ view: V) {
17 | let hosting = UIHostingController(rootView: view)
18 | hosting.view.translatesAutoresizingMaskIntoConstraints = false
19 | app.addChild(hosting)
20 | app.view.addSubview(hosting.view)
21 | NSLayoutConstraint.activate([
22 | hosting.view.leadingAnchor.constraint(equalTo: app.view.leadingAnchor),
23 | hosting.view.topAnchor.constraint(equalTo: app.view.topAnchor),
24 | hosting.view.trailingAnchor.constraint(equalTo: app.view.trailingAnchor),
25 | hosting.view.bottomAnchor.constraint(equalTo: app.view.bottomAnchor),
26 | ])
27 | app.view.layoutIfNeeded()
28 | }
29 | }
30 |
31 | struct SampleTestView: View {
32 | @RemoteData(endpoint: .feed) var feed: [Post]
33 |
34 | let resultSubject = PassthroughSubject<[Post], Never>()
35 |
36 | init() {
37 | print("init")
38 | }
39 |
40 | var body: some View {
41 | Text("This is just a test view...")
42 | .onAppear {
43 | print("on appear")
44 | resultSubject.send(feed)
45 | }
46 | .onChange(of: feed) { newFeed in
47 | print("on change: \(newFeed)")
48 | resultSubject.send(newFeed)
49 | }
50 | }
51 | }
52 |
53 | class SwiftUIPropertyWrapperTalkTests: CustomWrapperTest {
54 |
55 | var cancellables = Set()
56 |
57 | func testRemoteDataIsEventuallyAvailable() throws {
58 | let view = SampleTestView()
59 |
60 | let expect = expectation(description: "expected data to be loaded")
61 | view.resultSubject.sink { posts in
62 | if !posts.isEmpty {
63 | expect.fulfill()
64 | }
65 | }.store(in: &cancellables)
66 |
67 | host(view.environment(\.urlSession, URLSession.shared))
68 |
69 | waitForExpectations(timeout: 1)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk/RemoteData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RemoteData.swift
3 | // SwiftUIPropertyWrapperTalk
4 | //
5 | // Created by Donny Wals on 14/06/2022.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | private struct URLSessionKey: EnvironmentKey {
12 | static let defaultValue: URLSession = {
13 | URLSession.shared
14 | }()
15 | }
16 |
17 | extension EnvironmentValues {
18 | var urlSession: URLSession {
19 | get { self[URLSessionKey.self] }
20 | set { self[URLSessionKey.self] = newValue }
21 | }
22 | }
23 |
24 | @propertyWrapper
25 | struct RemoteData: DynamicProperty {
26 | @StateObject private var dataLoader = DataLoader()
27 | private let endpoint: Endpoint
28 |
29 | var wrappedValue: [Post] {
30 | dataLoader.loadedData
31 | }
32 |
33 | init(endpoint: Endpoint) {
34 | self.endpoint = endpoint
35 | }
36 |
37 | @Environment(\.urlSession) var urlSession
38 |
39 | func update() {
40 | if dataLoader.urlSession == nil || dataLoader.endpoint == nil {
41 | dataLoader.urlSession = urlSession
42 | dataLoader.endpoint = endpoint
43 | }
44 |
45 | dataLoader.fetchDataIfNeeded()
46 | }
47 | }
48 |
49 | class DataLoader: ObservableObject {
50 | @Published var loadedData: [Post] = []
51 | private var isLoadingData = false
52 |
53 | var urlSession: URLSession?
54 | var endpoint: RemoteData.Endpoint?
55 |
56 | init() { }
57 |
58 | func fetchDataIfNeeded() {
59 | guard let urlSession = urlSession, let endpoint = endpoint,
60 | !isLoadingData && loadedData.isEmpty else {
61 | return
62 | }
63 |
64 | isLoadingData = true
65 | let url = URL.for(endpoint)
66 | urlSession.dataTask(with: url) { data, response, error in
67 | guard let data = data else {
68 | /* ... */
69 | return
70 | }
71 |
72 | DispatchQueue.main.async {
73 | self.loadedData = try! JSONDecoder()
74 | .decode([Post].self, from: data)
75 | }
76 | self.isLoadingData = false
77 | }.resume()
78 | }
79 | }
80 |
81 | extension RemoteData {
82 | enum Endpoint {
83 | case feed
84 | }
85 | }
86 |
87 | extension URL {
88 | static func `for`(_ endpoint: RemoteData.Endpoint) -> URL {
89 | return URL(string: "https://donnywals.com/wp-json/wp/v2/posts")!
90 | }
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/SwiftUIPropertyWrapperTalk.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 979F2B3E2858FD3C000963F8 /* SwiftUIPropertyWrapperTalkApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979F2B3D2858FD3C000963F8 /* SwiftUIPropertyWrapperTalkApp.swift */; };
11 | 979F2B402858FD3C000963F8 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979F2B3F2858FD3C000963F8 /* ContentView.swift */; };
12 | 979F2B422858FD3D000963F8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 979F2B412858FD3D000963F8 /* Assets.xcassets */; };
13 | 979F2B452858FD3D000963F8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 979F2B442858FD3D000963F8 /* Preview Assets.xcassets */; };
14 | 979F2B4C285903CA000963F8 /* StringSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979F2B4B285903CA000963F8 /* StringSample.swift */; };
15 | 979F2B4E2859066E000963F8 /* RemoteData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979F2B4D2859066E000963F8 /* RemoteData.swift */; };
16 | 979F2B5028590A53000963F8 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979F2B4F28590A53000963F8 /* Post.swift */; };
17 | 979F2B58285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 979F2B57285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 979F2B59285A16A3000963F8 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 979F2B322858FD3C000963F8 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 979F2B392858FD3C000963F8;
26 | remoteInfo = SwiftUIPropertyWrapperTalk;
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | 979F2B3A2858FD3C000963F8 /* SwiftUIPropertyWrapperTalk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIPropertyWrapperTalk.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 979F2B3D2858FD3C000963F8 /* SwiftUIPropertyWrapperTalkApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIPropertyWrapperTalkApp.swift; sourceTree = ""; };
33 | 979F2B3F2858FD3C000963F8 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
34 | 979F2B412858FD3D000963F8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
35 | 979F2B442858FD3D000963F8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
36 | 979F2B4B285903CA000963F8 /* StringSample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringSample.swift; sourceTree = ""; };
37 | 979F2B4D2859066E000963F8 /* RemoteData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteData.swift; sourceTree = ""; };
38 | 979F2B4F28590A53000963F8 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; };
39 | 979F2B55285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftUIPropertyWrapperTalkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 979F2B57285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIPropertyWrapperTalkTests.swift; sourceTree = ""; };
41 | /* End PBXFileReference section */
42 |
43 | /* Begin PBXFrameworksBuildPhase section */
44 | 979F2B372858FD3C000963F8 /* Frameworks */ = {
45 | isa = PBXFrameworksBuildPhase;
46 | buildActionMask = 2147483647;
47 | files = (
48 | );
49 | runOnlyForDeploymentPostprocessing = 0;
50 | };
51 | 979F2B52285A16A3000963F8 /* Frameworks */ = {
52 | isa = PBXFrameworksBuildPhase;
53 | buildActionMask = 2147483647;
54 | files = (
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | /* End PBXFrameworksBuildPhase section */
59 |
60 | /* Begin PBXGroup section */
61 | 979F2B312858FD3C000963F8 = {
62 | isa = PBXGroup;
63 | children = (
64 | 979F2B3C2858FD3C000963F8 /* SwiftUIPropertyWrapperTalk */,
65 | 979F2B56285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests */,
66 | 979F2B3B2858FD3C000963F8 /* Products */,
67 | );
68 | sourceTree = "";
69 | };
70 | 979F2B3B2858FD3C000963F8 /* Products */ = {
71 | isa = PBXGroup;
72 | children = (
73 | 979F2B3A2858FD3C000963F8 /* SwiftUIPropertyWrapperTalk.app */,
74 | 979F2B55285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.xctest */,
75 | );
76 | name = Products;
77 | sourceTree = "";
78 | };
79 | 979F2B3C2858FD3C000963F8 /* SwiftUIPropertyWrapperTalk */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 979F2B3D2858FD3C000963F8 /* SwiftUIPropertyWrapperTalkApp.swift */,
83 | 979F2B4D2859066E000963F8 /* RemoteData.swift */,
84 | 979F2B3F2858FD3C000963F8 /* ContentView.swift */,
85 | 979F2B412858FD3D000963F8 /* Assets.xcassets */,
86 | 979F2B432858FD3D000963F8 /* Preview Content */,
87 | 979F2B4B285903CA000963F8 /* StringSample.swift */,
88 | 979F2B4F28590A53000963F8 /* Post.swift */,
89 | );
90 | path = SwiftUIPropertyWrapperTalk;
91 | sourceTree = "";
92 | };
93 | 979F2B432858FD3D000963F8 /* Preview Content */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 979F2B442858FD3D000963F8 /* Preview Assets.xcassets */,
97 | );
98 | path = "Preview Content";
99 | sourceTree = "";
100 | };
101 | 979F2B56285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 979F2B57285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.swift */,
105 | );
106 | path = SwiftUIPropertyWrapperTalkTests;
107 | sourceTree = "";
108 | };
109 | /* End PBXGroup section */
110 |
111 | /* Begin PBXNativeTarget section */
112 | 979F2B392858FD3C000963F8 /* SwiftUIPropertyWrapperTalk */ = {
113 | isa = PBXNativeTarget;
114 | buildConfigurationList = 979F2B482858FD3D000963F8 /* Build configuration list for PBXNativeTarget "SwiftUIPropertyWrapperTalk" */;
115 | buildPhases = (
116 | 979F2B362858FD3C000963F8 /* Sources */,
117 | 979F2B372858FD3C000963F8 /* Frameworks */,
118 | 979F2B382858FD3C000963F8 /* Resources */,
119 | );
120 | buildRules = (
121 | );
122 | dependencies = (
123 | );
124 | name = SwiftUIPropertyWrapperTalk;
125 | productName = SwiftUIPropertyWrapperTalk;
126 | productReference = 979F2B3A2858FD3C000963F8 /* SwiftUIPropertyWrapperTalk.app */;
127 | productType = "com.apple.product-type.application";
128 | };
129 | 979F2B54285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests */ = {
130 | isa = PBXNativeTarget;
131 | buildConfigurationList = 979F2B5B285A16A3000963F8 /* Build configuration list for PBXNativeTarget "SwiftUIPropertyWrapperTalkTests" */;
132 | buildPhases = (
133 | 979F2B51285A16A3000963F8 /* Sources */,
134 | 979F2B52285A16A3000963F8 /* Frameworks */,
135 | 979F2B53285A16A3000963F8 /* Resources */,
136 | );
137 | buildRules = (
138 | );
139 | dependencies = (
140 | 979F2B5A285A16A3000963F8 /* PBXTargetDependency */,
141 | );
142 | name = SwiftUIPropertyWrapperTalkTests;
143 | productName = SwiftUIPropertyWrapperTalkTests;
144 | productReference = 979F2B55285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.xctest */;
145 | productType = "com.apple.product-type.bundle.unit-test";
146 | };
147 | /* End PBXNativeTarget section */
148 |
149 | /* Begin PBXProject section */
150 | 979F2B322858FD3C000963F8 /* Project object */ = {
151 | isa = PBXProject;
152 | attributes = {
153 | BuildIndependentTargetsInParallel = 1;
154 | LastSwiftUpdateCheck = 1340;
155 | LastUpgradeCheck = 1340;
156 | TargetAttributes = {
157 | 979F2B392858FD3C000963F8 = {
158 | CreatedOnToolsVersion = 13.4;
159 | };
160 | 979F2B54285A16A3000963F8 = {
161 | CreatedOnToolsVersion = 13.4;
162 | TestTargetID = 979F2B392858FD3C000963F8;
163 | };
164 | };
165 | };
166 | buildConfigurationList = 979F2B352858FD3C000963F8 /* Build configuration list for PBXProject "SwiftUIPropertyWrapperTalk" */;
167 | compatibilityVersion = "Xcode 13.0";
168 | developmentRegion = en;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = 979F2B312858FD3C000963F8;
175 | productRefGroup = 979F2B3B2858FD3C000963F8 /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 979F2B392858FD3C000963F8 /* SwiftUIPropertyWrapperTalk */,
180 | 979F2B54285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests */,
181 | );
182 | };
183 | /* End PBXProject section */
184 |
185 | /* Begin PBXResourcesBuildPhase section */
186 | 979F2B382858FD3C000963F8 /* Resources */ = {
187 | isa = PBXResourcesBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | 979F2B452858FD3D000963F8 /* Preview Assets.xcassets in Resources */,
191 | 979F2B422858FD3D000963F8 /* Assets.xcassets in Resources */,
192 | );
193 | runOnlyForDeploymentPostprocessing = 0;
194 | };
195 | 979F2B53285A16A3000963F8 /* Resources */ = {
196 | isa = PBXResourcesBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | );
200 | runOnlyForDeploymentPostprocessing = 0;
201 | };
202 | /* End PBXResourcesBuildPhase section */
203 |
204 | /* Begin PBXSourcesBuildPhase section */
205 | 979F2B362858FD3C000963F8 /* Sources */ = {
206 | isa = PBXSourcesBuildPhase;
207 | buildActionMask = 2147483647;
208 | files = (
209 | 979F2B402858FD3C000963F8 /* ContentView.swift in Sources */,
210 | 979F2B4E2859066E000963F8 /* RemoteData.swift in Sources */,
211 | 979F2B4C285903CA000963F8 /* StringSample.swift in Sources */,
212 | 979F2B3E2858FD3C000963F8 /* SwiftUIPropertyWrapperTalkApp.swift in Sources */,
213 | 979F2B5028590A53000963F8 /* Post.swift in Sources */,
214 | );
215 | runOnlyForDeploymentPostprocessing = 0;
216 | };
217 | 979F2B51285A16A3000963F8 /* Sources */ = {
218 | isa = PBXSourcesBuildPhase;
219 | buildActionMask = 2147483647;
220 | files = (
221 | 979F2B58285A16A3000963F8 /* SwiftUIPropertyWrapperTalkTests.swift in Sources */,
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | };
225 | /* End PBXSourcesBuildPhase section */
226 |
227 | /* Begin PBXTargetDependency section */
228 | 979F2B5A285A16A3000963F8 /* PBXTargetDependency */ = {
229 | isa = PBXTargetDependency;
230 | target = 979F2B392858FD3C000963F8 /* SwiftUIPropertyWrapperTalk */;
231 | targetProxy = 979F2B59285A16A3000963F8 /* PBXContainerItemProxy */;
232 | };
233 | /* End PBXTargetDependency section */
234 |
235 | /* Begin XCBuildConfiguration section */
236 | 979F2B462858FD3D000963F8 /* Debug */ = {
237 | isa = XCBuildConfiguration;
238 | buildSettings = {
239 | ALWAYS_SEARCH_USER_PATHS = NO;
240 | CLANG_ANALYZER_NONNULL = YES;
241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
243 | CLANG_ENABLE_MODULES = YES;
244 | CLANG_ENABLE_OBJC_ARC = YES;
245 | CLANG_ENABLE_OBJC_WEAK = YES;
246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
247 | CLANG_WARN_BOOL_CONVERSION = YES;
248 | CLANG_WARN_COMMA = YES;
249 | CLANG_WARN_CONSTANT_CONVERSION = YES;
250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
252 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
253 | CLANG_WARN_EMPTY_BODY = YES;
254 | CLANG_WARN_ENUM_CONVERSION = YES;
255 | CLANG_WARN_INFINITE_RECURSION = YES;
256 | CLANG_WARN_INT_CONVERSION = YES;
257 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
258 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
259 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
261 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
263 | CLANG_WARN_STRICT_PROTOTYPES = YES;
264 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
266 | CLANG_WARN_UNREACHABLE_CODE = YES;
267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
268 | COPY_PHASE_STRIP = NO;
269 | DEBUG_INFORMATION_FORMAT = dwarf;
270 | ENABLE_STRICT_OBJC_MSGSEND = YES;
271 | ENABLE_TESTABILITY = YES;
272 | GCC_C_LANGUAGE_STANDARD = gnu11;
273 | GCC_DYNAMIC_NO_PIC = NO;
274 | GCC_NO_COMMON_BLOCKS = YES;
275 | GCC_OPTIMIZATION_LEVEL = 0;
276 | GCC_PREPROCESSOR_DEFINITIONS = (
277 | "DEBUG=1",
278 | "$(inherited)",
279 | );
280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
282 | GCC_WARN_UNDECLARED_SELECTOR = YES;
283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
284 | GCC_WARN_UNUSED_FUNCTION = YES;
285 | GCC_WARN_UNUSED_VARIABLE = YES;
286 | IPHONEOS_DEPLOYMENT_TARGET = 15.5;
287 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
288 | MTL_FAST_MATH = YES;
289 | ONLY_ACTIVE_ARCH = YES;
290 | SDKROOT = iphoneos;
291 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
292 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
293 | };
294 | name = Debug;
295 | };
296 | 979F2B472858FD3D000963F8 /* Release */ = {
297 | isa = XCBuildConfiguration;
298 | buildSettings = {
299 | ALWAYS_SEARCH_USER_PATHS = NO;
300 | CLANG_ANALYZER_NONNULL = YES;
301 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
303 | CLANG_ENABLE_MODULES = YES;
304 | CLANG_ENABLE_OBJC_ARC = YES;
305 | CLANG_ENABLE_OBJC_WEAK = YES;
306 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
307 | CLANG_WARN_BOOL_CONVERSION = YES;
308 | CLANG_WARN_COMMA = YES;
309 | CLANG_WARN_CONSTANT_CONVERSION = YES;
310 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
311 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
312 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
313 | CLANG_WARN_EMPTY_BODY = YES;
314 | CLANG_WARN_ENUM_CONVERSION = YES;
315 | CLANG_WARN_INFINITE_RECURSION = YES;
316 | CLANG_WARN_INT_CONVERSION = YES;
317 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
318 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
319 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
321 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
322 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
323 | CLANG_WARN_STRICT_PROTOTYPES = YES;
324 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
325 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
326 | CLANG_WARN_UNREACHABLE_CODE = YES;
327 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
328 | COPY_PHASE_STRIP = NO;
329 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
330 | ENABLE_NS_ASSERTIONS = NO;
331 | ENABLE_STRICT_OBJC_MSGSEND = YES;
332 | GCC_C_LANGUAGE_STANDARD = gnu11;
333 | GCC_NO_COMMON_BLOCKS = YES;
334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
336 | GCC_WARN_UNDECLARED_SELECTOR = YES;
337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
338 | GCC_WARN_UNUSED_FUNCTION = YES;
339 | GCC_WARN_UNUSED_VARIABLE = YES;
340 | IPHONEOS_DEPLOYMENT_TARGET = 15.5;
341 | MTL_ENABLE_DEBUG_INFO = NO;
342 | MTL_FAST_MATH = YES;
343 | SDKROOT = iphoneos;
344 | SWIFT_COMPILATION_MODE = wholemodule;
345 | SWIFT_OPTIMIZATION_LEVEL = "-O";
346 | VALIDATE_PRODUCT = YES;
347 | };
348 | name = Release;
349 | };
350 | 979F2B492858FD3D000963F8 /* Debug */ = {
351 | isa = XCBuildConfiguration;
352 | buildSettings = {
353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
354 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
355 | CODE_SIGN_STYLE = Automatic;
356 | CURRENT_PROJECT_VERSION = 1;
357 | DEVELOPMENT_ASSET_PATHS = "\"SwiftUIPropertyWrapperTalk/Preview Content\"";
358 | DEVELOPMENT_TEAM = 4JMM8JMG3H;
359 | ENABLE_PREVIEWS = YES;
360 | GENERATE_INFOPLIST_FILE = YES;
361 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
362 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
363 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
364 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
365 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
366 | LD_RUNPATH_SEARCH_PATHS = (
367 | "$(inherited)",
368 | "@executable_path/Frameworks",
369 | );
370 | MARKETING_VERSION = 1.0;
371 | PRODUCT_BUNDLE_IDENTIFIER = com.donnywals.SwiftUIPropertyWrapperTalk;
372 | PRODUCT_NAME = "$(TARGET_NAME)";
373 | SWIFT_EMIT_LOC_STRINGS = YES;
374 | SWIFT_VERSION = 5.0;
375 | TARGETED_DEVICE_FAMILY = "1,2";
376 | };
377 | name = Debug;
378 | };
379 | 979F2B4A2858FD3D000963F8 /* Release */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
383 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
384 | CODE_SIGN_STYLE = Automatic;
385 | CURRENT_PROJECT_VERSION = 1;
386 | DEVELOPMENT_ASSET_PATHS = "\"SwiftUIPropertyWrapperTalk/Preview Content\"";
387 | DEVELOPMENT_TEAM = 4JMM8JMG3H;
388 | ENABLE_PREVIEWS = YES;
389 | GENERATE_INFOPLIST_FILE = YES;
390 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
391 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
392 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
393 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
394 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
395 | LD_RUNPATH_SEARCH_PATHS = (
396 | "$(inherited)",
397 | "@executable_path/Frameworks",
398 | );
399 | MARKETING_VERSION = 1.0;
400 | PRODUCT_BUNDLE_IDENTIFIER = com.donnywals.SwiftUIPropertyWrapperTalk;
401 | PRODUCT_NAME = "$(TARGET_NAME)";
402 | SWIFT_EMIT_LOC_STRINGS = YES;
403 | SWIFT_VERSION = 5.0;
404 | TARGETED_DEVICE_FAMILY = "1,2";
405 | };
406 | name = Release;
407 | };
408 | 979F2B5C285A16A3000963F8 /* Debug */ = {
409 | isa = XCBuildConfiguration;
410 | buildSettings = {
411 | BUNDLE_LOADER = "$(TEST_HOST)";
412 | CODE_SIGN_STYLE = Automatic;
413 | CURRENT_PROJECT_VERSION = 1;
414 | DEVELOPMENT_TEAM = 4JMM8JMG3H;
415 | GENERATE_INFOPLIST_FILE = YES;
416 | MARKETING_VERSION = 1.0;
417 | PRODUCT_BUNDLE_IDENTIFIER = com.donnywals.SwiftUIPropertyWrapperTalkTests;
418 | PRODUCT_NAME = "$(TARGET_NAME)";
419 | SWIFT_EMIT_LOC_STRINGS = NO;
420 | SWIFT_VERSION = 5.0;
421 | TARGETED_DEVICE_FAMILY = "1,2";
422 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUIPropertyWrapperTalk.app/SwiftUIPropertyWrapperTalk";
423 | };
424 | name = Debug;
425 | };
426 | 979F2B5D285A16A3000963F8 /* Release */ = {
427 | isa = XCBuildConfiguration;
428 | buildSettings = {
429 | BUNDLE_LOADER = "$(TEST_HOST)";
430 | CODE_SIGN_STYLE = Automatic;
431 | CURRENT_PROJECT_VERSION = 1;
432 | DEVELOPMENT_TEAM = 4JMM8JMG3H;
433 | GENERATE_INFOPLIST_FILE = YES;
434 | MARKETING_VERSION = 1.0;
435 | PRODUCT_BUNDLE_IDENTIFIER = com.donnywals.SwiftUIPropertyWrapperTalkTests;
436 | PRODUCT_NAME = "$(TARGET_NAME)";
437 | SWIFT_EMIT_LOC_STRINGS = NO;
438 | SWIFT_VERSION = 5.0;
439 | TARGETED_DEVICE_FAMILY = "1,2";
440 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUIPropertyWrapperTalk.app/SwiftUIPropertyWrapperTalk";
441 | };
442 | name = Release;
443 | };
444 | /* End XCBuildConfiguration section */
445 |
446 | /* Begin XCConfigurationList section */
447 | 979F2B352858FD3C000963F8 /* Build configuration list for PBXProject "SwiftUIPropertyWrapperTalk" */ = {
448 | isa = XCConfigurationList;
449 | buildConfigurations = (
450 | 979F2B462858FD3D000963F8 /* Debug */,
451 | 979F2B472858FD3D000963F8 /* Release */,
452 | );
453 | defaultConfigurationIsVisible = 0;
454 | defaultConfigurationName = Release;
455 | };
456 | 979F2B482858FD3D000963F8 /* Build configuration list for PBXNativeTarget "SwiftUIPropertyWrapperTalk" */ = {
457 | isa = XCConfigurationList;
458 | buildConfigurations = (
459 | 979F2B492858FD3D000963F8 /* Debug */,
460 | 979F2B4A2858FD3D000963F8 /* Release */,
461 | );
462 | defaultConfigurationIsVisible = 0;
463 | defaultConfigurationName = Release;
464 | };
465 | 979F2B5B285A16A3000963F8 /* Build configuration list for PBXNativeTarget "SwiftUIPropertyWrapperTalkTests" */ = {
466 | isa = XCConfigurationList;
467 | buildConfigurations = (
468 | 979F2B5C285A16A3000963F8 /* Debug */,
469 | 979F2B5D285A16A3000963F8 /* Release */,
470 | );
471 | defaultConfigurationIsVisible = 0;
472 | defaultConfigurationName = Release;
473 | };
474 | /* End XCConfigurationList section */
475 | };
476 | rootObject = 979F2B322858FD3C000963F8 /* Project object */;
477 | }
478 |
--------------------------------------------------------------------------------