├── .gitignore ├── testable-view-swiftui ├── Assets.xcassets │ ├── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── Sheet.swift ├── ContentModel.swift ├── ContentViewModel.swift ├── Main.swift ├── RealApp.swift ├── TestApp.swift ├── ContentModel+View.swift ├── ContentView.swift └── TestingSupport.swift ├── testable-view-swiftui.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcshareddata │ └── xcschemes │ │ └── testable-view-swiftui.xcscheme └── project.pbxproj ├── testable-view-swiftui.xctestplan ├── testable-view-swiftuiTests ├── NativeBusinessLogicTests.swift └── ViewInspectorBodyTests.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | testable-view-swiftui.xcodeproj/xcuserdata 2 | -------------------------------------------------------------------------------- /testable-view-swiftui/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testable-view-swiftui/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testable-view-swiftui.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testable-view-swiftui/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 | -------------------------------------------------------------------------------- /testable-view-swiftui/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /testable-view-swiftui.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testable-view-swiftui/Sheet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sheet.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 25.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct Sheet: View { 11 | var body: some View { 12 | let _ = assert(bodyAssertion) 13 | Text("This is sheet") 14 | } 15 | } 16 | 17 | #Preview { 18 | Sheet() 19 | } 20 | -------------------------------------------------------------------------------- /testable-view-swiftui/ContentModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentViewModelView.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 23.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentModel { 11 | @State var sheetShown = false 12 | @State var counter = 0 13 | func increase() { counter += 1 } 14 | func showSheet() { sheetShown.toggle() } 15 | } 16 | -------------------------------------------------------------------------------- /testable-view-swiftui/ContentViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentViewModel.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 24.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @Observable final class ContentViewModel { 11 | var sheetShown = false 12 | var counter = 0 13 | func increase() { counter += 1 } 14 | func showSheet() { sheetShown.toggle() } 15 | } 16 | -------------------------------------------------------------------------------- /testable-view-swiftui/Main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // testable_view_swiftuiApp.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 22.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main enum Main { 11 | static func main() { 12 | if NSClassFromString("XCTestCase") != nil { 13 | TestApp.main() 14 | } else { 15 | RealApp.main() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testable-view-swiftui/RealApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealApp.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 24.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct RealApp: App { 11 | var body: some Scene { 12 | WindowGroup { 13 | VStack(spacing: 64) { 14 | ContentView() 15 | ContentModel() 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /testable-view-swiftui/TestApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestApp.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 24.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TestApp: App { 11 | static var shared: Self! 12 | @State var view: any View = EmptyView() 13 | var body: some Scene { 14 | let _ = Self.shared = self 15 | WindowGroup { 16 | AnyView(view) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /testable-view-swiftui.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "viewinspector", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/nalexn/ViewInspector.git", 7 | "state" : { 8 | "revision" : "a1422d4749ccf7f32b1d14a9ec19ec9a0b0fd337", 9 | "version" : "0.9.9" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /testable-view-swiftui/ContentModel+View.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentModel+View.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 24.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | extension ContentModel: View { 11 | var body: some View { 12 | let _ = assert(bodyAssertion) 13 | VStack { 14 | Text("The counter value is \(counter)") 15 | Button("Increase", action: increase) 16 | Button("Show sheet", action: showSheet) 17 | } 18 | .sheet(isPresented: $sheetShown) { 19 | Sheet() 20 | } 21 | } 22 | } 23 | 24 | #Preview { 25 | ContentModel() 26 | } 27 | -------------------------------------------------------------------------------- /testable-view-swiftui/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 22.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | @State var vm = ContentViewModel() 12 | var body: some View { 13 | let _ = assert(bodyAssertion) 14 | VStack { 15 | Text("The counter value is \(vm.counter)") 16 | Button("Increase", action: vm.increase) 17 | Button("Show sheet", action: vm.showSheet) 18 | } 19 | .sheet(isPresented: $vm.sheetShown) { 20 | Sheet() 21 | } 22 | } 23 | } 24 | 25 | #Preview { 26 | ContentView() 27 | } 28 | -------------------------------------------------------------------------------- /testable-view-swiftui/TestingSupport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestingSupport.swift 3 | // testable-view-swiftui 4 | // 5 | // Created by Lazar Otasevic on 23.12.23.. 6 | // 7 | 8 | import Combine 9 | import SwiftUI 10 | 11 | extension Publisher { 12 | func enumerated() -> AnyPublisher<(Int, Output), Failure> { 13 | scan(nil) { acc, next in 14 | (acc.map { $0.0 + 1 } ?? 0, next) 15 | } 16 | .compactMap { $0 } 17 | .eraseToAnyPublisher() 18 | } 19 | } 20 | 21 | extension View { 22 | private static var bodyEvaluationNotification: Notification.Name { Notification.Name("bodyEvaluationNotification") } 23 | 24 | var bodyAssertion: Bool { 25 | Self._printChanges() 26 | NotificationCenter.default.post(name: Self.bodyEvaluationNotification, object: self) 27 | return true 28 | } 29 | 30 | static func bodyEvaluations() -> AsyncPublisher> { 31 | NotificationCenter.default 32 | .publisher(for: bodyEvaluationNotification) 33 | .compactMap { $0.object as? Self } 34 | .enumerated().values 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /testable-view-swiftui.xctestplan: -------------------------------------------------------------------------------- 1 | { 2 | "configurations" : [ 3 | { 4 | "id" : "006E6665-2AD1-4D58-89A2-3318F0BB5D13", 5 | "name" : "Test Scheme Action", 6 | "options" : { 7 | "defaultTestExecutionTimeAllowance" : 60, 8 | "testTimeoutsEnabled" : true 9 | } 10 | } 11 | ], 12 | "defaultOptions" : { 13 | "codeCoverage" : { 14 | "targets" : [ 15 | { 16 | "containerPath" : "container:testable-view-swiftui.xcodeproj", 17 | "identifier" : "7E13782E2B360A1B00C83B78", 18 | "name" : "testable-view-swiftui" 19 | }, 20 | { 21 | "containerPath" : "container:testable-view-swiftui.xcodeproj", 22 | "identifier" : "7E13783E2B360A1D00C83B78", 23 | "name" : "testable-view-swiftuiTests" 24 | } 25 | ] 26 | }, 27 | "targetForVariableExpansion" : { 28 | "containerPath" : "container:testable-view-swiftui.xcodeproj", 29 | "identifier" : "7E13782E2B360A1B00C83B78", 30 | "name" : "testable-view-swiftui" 31 | } 32 | }, 33 | "testTargets" : [ 34 | { 35 | "target" : { 36 | "containerPath" : "container:testable-view-swiftui.xcodeproj", 37 | "identifier" : "7E13783E2B360A1D00C83B78", 38 | "name" : "testable-view-swiftuiTests" 39 | } 40 | } 41 | ], 42 | "version" : 1 43 | } 44 | -------------------------------------------------------------------------------- /testable-view-swiftuiTests/NativeBusinessLogicTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // testable_view_swiftuiTests.swift 3 | // testable-view-swiftuiTests 4 | // 5 | // Created by Lazar Otasevic on 22.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | @testable import testable_view_swiftui 10 | import XCTest 11 | 12 | final class NativeBusinessLogicTests: XCTestCase {} 13 | 14 | @MainActor extension NativeBusinessLogicTests { 15 | func testContenModel() async throws { 16 | TestApp.shared.view = ContentModel() 17 | for await (index, view) in ContentModel.bodyEvaluations().prefix(2) { 18 | switch index { 19 | case 0: 20 | XCTAssertEqual(view.counter, 0) 21 | view.increase() 22 | case 1: 23 | XCTAssertEqual(view.counter, 1) 24 | view.showSheet() 25 | for await _ in Sheet.bodyEvaluations().prefix(1) {} 26 | default: break 27 | } 28 | } 29 | } 30 | 31 | func testContentView() async throws { 32 | TestApp.shared.view = ContentView() 33 | for await (index, view) in ContentView.bodyEvaluations().prefix(2) { 34 | switch index { 35 | case 0: 36 | XCTAssertEqual(view.vm.counter, 0) 37 | view.vm.increase() 38 | case 1: 39 | XCTAssertEqual(view.vm.counter, 1) 40 | view.vm.showSheet() 41 | for await _ in Sheet.bodyEvaluations().prefix(1) {} 42 | default: break 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /testable-view-swiftuiTests/ViewInspectorBodyTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BodyTests.swift 3 | // testable-view-swiftuiTests 4 | // 5 | // Created by Lazar Otasevic on 24.12.23.. 6 | // 7 | 8 | import SwiftUI 9 | @testable import testable_view_swiftui 10 | import ViewInspector 11 | import XCTest 12 | 13 | final class ViewInspectorBodyTests: XCTestCase {} 14 | 15 | @MainActor extension ViewInspectorBodyTests { 16 | func testContenModel() async throws { 17 | TestApp.shared.view = ContentModel() 18 | for await (index, view) in ContentModel.bodyEvaluations().prefix(2) { 19 | switch index { 20 | case 0: 21 | _ = try view.inspect().find(text: "The counter value is 0") 22 | try view.inspect().find(button: "Increase").tap() 23 | case 1: 24 | _ = try view.inspect().find(text: "The counter value is 1") 25 | try view.inspect().find(button: "Show sheet").tap() 26 | for await (_, view) in Sheet.bodyEvaluations().prefix(1) { 27 | _ = try view.inspect().find(text: "This is sheet") 28 | } 29 | default: break 30 | } 31 | } 32 | } 33 | 34 | func testContentView() async throws { 35 | TestApp.shared.view = ContentView() 36 | for await (index, view) in ContentView.bodyEvaluations().prefix(2) { 37 | switch index { 38 | case 0: 39 | _ = try view.inspect().find(text: "The counter value is 0") 40 | try view.inspect().find(button: "Increase").tap() 41 | case 1: 42 | _ = try view.inspect().find(text: "The counter value is 1") 43 | try view.inspect().find(button: "Show sheet").tap() 44 | for await (_, view) in Sheet.bodyEvaluations().prefix(1) { 45 | _ = try view.inspect().find(text: "This is sheet") 46 | } 47 | default: break 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /testable-view-swiftui.xcodeproj/xcshareddata/xcschemes/testable-view-swiftui.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 34 | 35 | 36 | 37 | 39 | 45 | 46 | 47 | 50 | 56 | 57 | 58 | 59 | 60 | 70 | 72 | 78 | 79 | 80 | 81 | 87 | 89 | 95 | 96 | 97 | 98 | 100 | 101 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Testable SwiftUI views using async/await 2 | 3 | - This example demonstrates how to test any `SwiftUI.View` without hacks or third-party libraries, accomplished in just a few minutes of coding. 4 | - We compare SwiftUI and MVVM and show that the `Observable` view-model approach may not be the best fit for SwiftUI, as it doesn't align well with its paradigm. 5 | 6 | Short overview of the code: 7 | - [Test app](https://github.com/sisoje/testable-view-swiftui/blob/main/testable-view-swiftui/TestApp.swift) 8 | - [Testing support](https://github.com/sisoje/testable-view-swiftui/blob/main/testable-view-swiftui/TestingSupport.swift) 9 | - [Testable view-body](https://github.com/sisoje/testable-view-swiftui/blob/main/testable-view-swiftui/Sheet.swift) 10 | - [Actual test](https://github.com/sisoje/testable-view-swiftui/blob/main/testable-view-swiftuiTests/ViewInspectorBodyTests.swift) 11 | 12 | 13 | `SwiftUI.View` is just a protocol that only value types can conform to, its centerpiece being the `body` property, which produces another `SwiftUI.View`. 14 | 15 | It lacks typical view properties like frame or color. This implies that `SwiftUI.View` isn't a traditional view. 16 | 17 | `SwiftUI.View` looks and acts more like a view-model. Understanding this is key to grasping the essence of `SwiftUI.View`. 18 | 19 | # SwiftUI model vs MVVM view-model 20 | 21 | Anyone claiming how Apple coupled view and business logic is wrong. Apple just used View conformance on top of the model. That is not coupling. That is POP. 22 | 23 | In SwiftUI it is up to you what goes to model and what goes to View conformance extension. Don't blame Apple if your code is entangled. 24 | 25 | MVVM uses **HARD** decoupling which is more suitable for Java and other old-school languages. 26 | 27 | We start with two similar implementations of our business logic: 28 | ``` 29 | struct ContentModel { 30 | @State var sheetShown = false 31 | @State var counter = 0 32 | func increase() { counter += 1 } 33 | func showSheet() { sheetShown.toggle() } 34 | } 35 | 36 | @Observable final class ContentViewModel { 37 | var sheetShown = false 38 | var counter = 0 39 | func increase() { counter += 1 } 40 | func showSheet() { sheetShown.toggle() } 41 | } 42 | ``` 43 | 44 | # Model conformance vs VM composition 45 | 46 | We can make two view variants, one is SwiftUI and the other is MVVM. One uses conformance and the other uses composition. 47 | ``` 48 | extension ContentModel: View { 49 | var body: some View { 50 | let _ = assert(bodyAssertion) // this is the only line in the view for testing support 51 | VStack { 52 | Text("The counter value is \(counter)") 53 | Button("Increase", action: increase) 54 | Button("Show sheet", action: showSheet) 55 | } 56 | .sheet(isPresented: $sheetShown) { 57 | Sheet() 58 | } 59 | } 60 | } 61 | 62 | struct ContentView: View { 63 | @State var vm = ContentViewModel() 64 | var body: some View { 65 | let _ = assert(bodyAssertion) // this is the only line in the view for testing support 66 | VStack { 67 | Text("The counter value is \(vm.counter)") 68 | Button("Increase", action: vm.increase) 69 | Button("Show sheet", action: vm.showSheet) 70 | } 71 | .sheet(isPresented: $vm.sheetShown) { 72 | Sheet() 73 | } 74 | } 75 | } 76 | ``` 77 | 78 | # Native async/await testing 79 | 80 | ### App hosting 81 | 82 | The key for view testing is to host the View in some App. 83 | 84 | We need to share the state, that is the hosted view, between the main-target and the test-target: 85 | ``` 86 | struct TestApp: App { 87 | static var shared: Self! 88 | @State var view: any View = EmptyView() 89 | var body: some Scene { 90 | let _ = Self.shared = self 91 | WindowGroup { 92 | AnyView(view) 93 | } 94 | } 95 | } 96 | ``` 97 | ### Body evaluation notifications 98 | 99 | We need to notify the test function that body evaluation happened. To achieve this is we add `let _ = assert(bodyAssertion)` as the first line of the body. 100 | 101 | **NOTE: Assertion does not evaluate in release! We dont need #if DEBUG ...** 102 | 103 | ### Tests 104 | 105 | We can test both SwiftUI and MVVM versions in the same way, no hacking, no third party libs. 106 | 107 | We receive body-evaluation index and the view itself as an async sequence from our 30-lines of code "framework" so we can test if the evaluations behave like we intended: 108 | ``` 109 | func testContenModel() async throws { 110 | TestApp.shared.view = ContentModel() 111 | for await (index, view) in ContentModel.bodyEvaluations().prefix(2) { 112 | switch index { 113 | case 0: 114 | XCTAssertEqual(view.counter, 0) 115 | view.increase() 116 | case 1: 117 | XCTAssertEqual(view.counter, 1) 118 | view.showSheet() 119 | default: break 120 | } 121 | } 122 | } 123 | 124 | func testContentView() async throws { 125 | TestApp.shared.view = ContentView() 126 | for await (index, view) in ContentView.bodyEvaluations().prefix(2) { 127 | switch index { 128 | case 0: 129 | XCTAssertEqual(view.vm.counter, 0) 130 | view.vm.increase() 131 | case 1: 132 | XCTAssertEqual(view.vm.counter, 1) 133 | view.vm.showSheet() 134 | default: break 135 | } 136 | } 137 | } 138 | ``` 139 | 140 | # Testing UI interactions using ViewInspector 141 | 142 | Testing the body function using tools like ViewInspector, in conjunction with our native testing approach, allows us to interact with SwiftUI elements and to verify their values with each interaction. 143 | 144 | Tests are identical for both SwiftUI and MVVM: 145 | ``` 146 | switch index { 147 | case 0: 148 | _ = try view.inspect().find(text: "The counter value is 0") 149 | try view.inspect().find(button: "Increase").tap() 150 | case 1: 151 | _ = try view.inspect().find(text: "The counter value is 1") 152 | try view.inspect().find(button: "Show sheet").tap() 153 | default: break 154 | } 155 | ``` 156 | 157 | # Body evaluations during the ViewInspector test 158 | 159 | Test findings spotlight a disparity in number of body evaluations. 160 | 161 | MVVM approach necessitates more evaluations of the view’s body, underscoring a potential inefficiency in how MVVM patterns integrate with SwiftUI’s rendering cycle. 162 | 163 | ### 2 body evaluations using SwiftUI 164 | ``` 165 | ContentModel: @self, @identity, _sheetShown, _counter changed. 166 | ContentModel: _counter changed. 167 | ``` 168 | 169 | ### 3 body evaluations using MVVM 170 | ``` 171 | ContentView: @self, @identity, _vm changed. 172 | ContentView: @dependencies changed. 173 | ContentView: @dependencies changed. 174 | ``` 175 | 176 | # Design flaws of MVVM in SwiftUI 177 | 178 | - My biggest issue with MVVM is inability to use native property wrappers like @Environment, @AppStorage, @Query and others. 179 | - View-models are not composable, while SwiftUI models(views) are very easy to split and reuse. MVVM just leads us to massive views and massive view-models. Its harder to split to smaller components. You need double amount of work to split them. You need to split VM and the View each on its own. 180 | - Another problem with MVVM is usage of reference types. Using `[weak self]` everywhere is so annoying and misuse can lead to reference cycles. 181 | 182 | Now that we know how to test "views" there is really no need to use MVVM. 183 | -------------------------------------------------------------------------------- /testable-view-swiftui.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7E1378332B360A1B00C83B78 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378322B360A1B00C83B78 /* Main.swift */; }; 11 | 7E1378352B360A1B00C83B78 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378342B360A1B00C83B78 /* ContentView.swift */; }; 12 | 7E1378372B360A1D00C83B78 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7E1378362B360A1D00C83B78 /* Assets.xcassets */; }; 13 | 7E13783A2B360A1D00C83B78 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7E1378392B360A1D00C83B78 /* Preview Assets.xcassets */; }; 14 | 7E1378442B360A1D00C83B78 /* NativeBusinessLogicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378432B360A1D00C83B78 /* NativeBusinessLogicTests.swift */; }; 15 | 7E13785D2B37032D00C83B78 /* TestingSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E13785C2B37032D00C83B78 /* TestingSupport.swift */; }; 16 | 7E13785F2B370A3800C83B78 /* ContentModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E13785E2B370A3800C83B78 /* ContentModel.swift */; }; 17 | 7E1378662B37A62700C83B78 /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378652B37A62700C83B78 /* ContentViewModel.swift */; }; 18 | 7E13788A2B3889B800C83B78 /* TestApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378892B3889B800C83B78 /* TestApp.swift */; }; 19 | 7E13788C2B3889D200C83B78 /* RealApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E13788B2B3889D200C83B78 /* RealApp.swift */; }; 20 | 7E13788E2B388A6D00C83B78 /* ContentModel+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E13788D2B388A6D00C83B78 /* ContentModel+View.swift */; }; 21 | 7E1378912B38C21B00C83B78 /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 7E1378902B38C21B00C83B78 /* ViewInspector */; }; 22 | 7E1378932B38C73400C83B78 /* ViewInspectorBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378922B38C73400C83B78 /* ViewInspectorBodyTests.swift */; }; 23 | 7E1378992B3995C000C83B78 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1378982B3995C000C83B78 /* Sheet.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 7E1378402B360A1D00C83B78 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 7E1378272B360A1B00C83B78 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 7E13782E2B360A1B00C83B78; 32 | remoteInfo = "testable-view-swiftui"; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 7E13782F2B360A1B00C83B78 /* testable-view-swiftui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "testable-view-swiftui.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 7E1378322B360A1B00C83B78 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; }; 39 | 7E1378342B360A1B00C83B78 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 40 | 7E1378362B360A1D00C83B78 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 41 | 7E1378392B360A1D00C83B78 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 42 | 7E13783F2B360A1D00C83B78 /* testable-view-swiftuiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "testable-view-swiftuiTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 7E1378432B360A1D00C83B78 /* NativeBusinessLogicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeBusinessLogicTests.swift; sourceTree = ""; }; 44 | 7E13785C2B37032D00C83B78 /* TestingSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingSupport.swift; sourceTree = ""; }; 45 | 7E13785E2B370A3800C83B78 /* ContentModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentModel.swift; sourceTree = ""; }; 46 | 7E1378632B3790FC00C83B78 /* testable-view-swiftui.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "testable-view-swiftui.xctestplan"; sourceTree = ""; }; 47 | 7E1378642B37915700C83B78 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 48 | 7E1378652B37A62700C83B78 /* ContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; }; 49 | 7E1378892B3889B800C83B78 /* TestApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestApp.swift; sourceTree = ""; }; 50 | 7E13788B2B3889D200C83B78 /* RealApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealApp.swift; sourceTree = ""; }; 51 | 7E13788D2B388A6D00C83B78 /* ContentModel+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContentModel+View.swift"; sourceTree = ""; }; 52 | 7E1378922B38C73400C83B78 /* ViewInspectorBodyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewInspectorBodyTests.swift; sourceTree = ""; }; 53 | 7E1378982B3995C000C83B78 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | 7E13782C2B360A1B00C83B78 /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | 7E13783C2B360A1D00C83B78 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 7E1378912B38C21B00C83B78 /* ViewInspector in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXFrameworksBuildPhase section */ 73 | 74 | /* Begin PBXGroup section */ 75 | 7E1378262B360A1B00C83B78 = { 76 | isa = PBXGroup; 77 | children = ( 78 | 7E1378642B37915700C83B78 /* README.md */, 79 | 7E1378632B3790FC00C83B78 /* testable-view-swiftui.xctestplan */, 80 | 7E1378312B360A1B00C83B78 /* testable-view-swiftui */, 81 | 7E1378422B360A1D00C83B78 /* testable-view-swiftuiTests */, 82 | 7E1378302B360A1B00C83B78 /* Products */, 83 | ); 84 | sourceTree = ""; 85 | }; 86 | 7E1378302B360A1B00C83B78 /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 7E13782F2B360A1B00C83B78 /* testable-view-swiftui.app */, 90 | 7E13783F2B360A1D00C83B78 /* testable-view-swiftuiTests.xctest */, 91 | ); 92 | name = Products; 93 | sourceTree = ""; 94 | }; 95 | 7E1378312B360A1B00C83B78 /* testable-view-swiftui */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 7E13785E2B370A3800C83B78 /* ContentModel.swift */, 99 | 7E1378982B3995C000C83B78 /* Sheet.swift */, 100 | 7E13788D2B388A6D00C83B78 /* ContentModel+View.swift */, 101 | 7E1378342B360A1B00C83B78 /* ContentView.swift */, 102 | 7E1378652B37A62700C83B78 /* ContentViewModel.swift */, 103 | 7E1378322B360A1B00C83B78 /* Main.swift */, 104 | 7E13788B2B3889D200C83B78 /* RealApp.swift */, 105 | 7E1378892B3889B800C83B78 /* TestApp.swift */, 106 | 7E13785C2B37032D00C83B78 /* TestingSupport.swift */, 107 | 7E1378362B360A1D00C83B78 /* Assets.xcassets */, 108 | 7E1378382B360A1D00C83B78 /* Preview Content */, 109 | ); 110 | path = "testable-view-swiftui"; 111 | sourceTree = ""; 112 | }; 113 | 7E1378382B360A1D00C83B78 /* Preview Content */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 7E1378392B360A1D00C83B78 /* Preview Assets.xcassets */, 117 | ); 118 | path = "Preview Content"; 119 | sourceTree = ""; 120 | }; 121 | 7E1378422B360A1D00C83B78 /* testable-view-swiftuiTests */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 7E1378432B360A1D00C83B78 /* NativeBusinessLogicTests.swift */, 125 | 7E1378922B38C73400C83B78 /* ViewInspectorBodyTests.swift */, 126 | ); 127 | path = "testable-view-swiftuiTests"; 128 | sourceTree = ""; 129 | }; 130 | /* End PBXGroup section */ 131 | 132 | /* Begin PBXNativeTarget section */ 133 | 7E13782E2B360A1B00C83B78 /* testable-view-swiftui */ = { 134 | isa = PBXNativeTarget; 135 | buildConfigurationList = 7E1378532B360A1D00C83B78 /* Build configuration list for PBXNativeTarget "testable-view-swiftui" */; 136 | buildPhases = ( 137 | 7E13782B2B360A1B00C83B78 /* Sources */, 138 | 7E13782C2B360A1B00C83B78 /* Frameworks */, 139 | 7E13782D2B360A1B00C83B78 /* Resources */, 140 | ); 141 | buildRules = ( 142 | ); 143 | dependencies = ( 144 | ); 145 | name = "testable-view-swiftui"; 146 | productName = "testable-view-swiftui"; 147 | productReference = 7E13782F2B360A1B00C83B78 /* testable-view-swiftui.app */; 148 | productType = "com.apple.product-type.application"; 149 | }; 150 | 7E13783E2B360A1D00C83B78 /* testable-view-swiftuiTests */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = 7E1378562B360A1D00C83B78 /* Build configuration list for PBXNativeTarget "testable-view-swiftuiTests" */; 153 | buildPhases = ( 154 | 7E13783B2B360A1D00C83B78 /* Sources */, 155 | 7E13783C2B360A1D00C83B78 /* Frameworks */, 156 | 7E13783D2B360A1D00C83B78 /* Resources */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | 7E1378412B360A1D00C83B78 /* PBXTargetDependency */, 162 | ); 163 | name = "testable-view-swiftuiTests"; 164 | packageProductDependencies = ( 165 | 7E1378902B38C21B00C83B78 /* ViewInspector */, 166 | ); 167 | productName = "testable-view-swiftuiTests"; 168 | productReference = 7E13783F2B360A1D00C83B78 /* testable-view-swiftuiTests.xctest */; 169 | productType = "com.apple.product-type.bundle.unit-test"; 170 | }; 171 | /* End PBXNativeTarget section */ 172 | 173 | /* Begin PBXProject section */ 174 | 7E1378272B360A1B00C83B78 /* Project object */ = { 175 | isa = PBXProject; 176 | attributes = { 177 | BuildIndependentTargetsInParallel = 1; 178 | LastSwiftUpdateCheck = 1510; 179 | LastUpgradeCheck = 1510; 180 | TargetAttributes = { 181 | 7E13782E2B360A1B00C83B78 = { 182 | CreatedOnToolsVersion = 15.1; 183 | }; 184 | 7E13783E2B360A1D00C83B78 = { 185 | CreatedOnToolsVersion = 15.1; 186 | TestTargetID = 7E13782E2B360A1B00C83B78; 187 | }; 188 | }; 189 | }; 190 | buildConfigurationList = 7E13782A2B360A1B00C83B78 /* Build configuration list for PBXProject "testable-view-swiftui" */; 191 | compatibilityVersion = "Xcode 14.0"; 192 | developmentRegion = en; 193 | hasScannedForEncodings = 0; 194 | knownRegions = ( 195 | en, 196 | Base, 197 | ); 198 | mainGroup = 7E1378262B360A1B00C83B78; 199 | packageReferences = ( 200 | 7E13788F2B38C21B00C83B78 /* XCRemoteSwiftPackageReference "ViewInspector" */, 201 | ); 202 | productRefGroup = 7E1378302B360A1B00C83B78 /* Products */; 203 | projectDirPath = ""; 204 | projectRoot = ""; 205 | targets = ( 206 | 7E13782E2B360A1B00C83B78 /* testable-view-swiftui */, 207 | 7E13783E2B360A1D00C83B78 /* testable-view-swiftuiTests */, 208 | ); 209 | }; 210 | /* End PBXProject section */ 211 | 212 | /* Begin PBXResourcesBuildPhase section */ 213 | 7E13782D2B360A1B00C83B78 /* Resources */ = { 214 | isa = PBXResourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | 7E13783A2B360A1D00C83B78 /* Preview Assets.xcassets in Resources */, 218 | 7E1378372B360A1D00C83B78 /* Assets.xcassets in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | 7E13783D2B360A1D00C83B78 /* Resources */ = { 223 | isa = PBXResourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXResourcesBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 7E13782B2B360A1B00C83B78 /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 7E13785D2B37032D00C83B78 /* TestingSupport.swift in Sources */, 237 | 7E1378352B360A1B00C83B78 /* ContentView.swift in Sources */, 238 | 7E1378332B360A1B00C83B78 /* Main.swift in Sources */, 239 | 7E1378992B3995C000C83B78 /* Sheet.swift in Sources */, 240 | 7E13785F2B370A3800C83B78 /* ContentModel.swift in Sources */, 241 | 7E13788E2B388A6D00C83B78 /* ContentModel+View.swift in Sources */, 242 | 7E1378662B37A62700C83B78 /* ContentViewModel.swift in Sources */, 243 | 7E13788A2B3889B800C83B78 /* TestApp.swift in Sources */, 244 | 7E13788C2B3889D200C83B78 /* RealApp.swift in Sources */, 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | }; 248 | 7E13783B2B360A1D00C83B78 /* Sources */ = { 249 | isa = PBXSourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | 7E1378442B360A1D00C83B78 /* NativeBusinessLogicTests.swift in Sources */, 253 | 7E1378932B38C73400C83B78 /* ViewInspectorBodyTests.swift in Sources */, 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | /* End PBXSourcesBuildPhase section */ 258 | 259 | /* Begin PBXTargetDependency section */ 260 | 7E1378412B360A1D00C83B78 /* PBXTargetDependency */ = { 261 | isa = PBXTargetDependency; 262 | target = 7E13782E2B360A1B00C83B78 /* testable-view-swiftui */; 263 | targetProxy = 7E1378402B360A1D00C83B78 /* PBXContainerItemProxy */; 264 | }; 265 | /* End PBXTargetDependency section */ 266 | 267 | /* Begin XCBuildConfiguration section */ 268 | 7E1378512B360A1D00C83B78 /* Debug */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ALWAYS_SEARCH_USER_PATHS = NO; 272 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 273 | CLANG_ANALYZER_NONNULL = YES; 274 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 275 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 276 | CLANG_ENABLE_MODULES = YES; 277 | CLANG_ENABLE_OBJC_ARC = YES; 278 | CLANG_ENABLE_OBJC_WEAK = YES; 279 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 280 | CLANG_WARN_BOOL_CONVERSION = YES; 281 | CLANG_WARN_COMMA = YES; 282 | CLANG_WARN_CONSTANT_CONVERSION = YES; 283 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 285 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN_ENUM_CONVERSION = YES; 288 | CLANG_WARN_INFINITE_RECURSION = YES; 289 | CLANG_WARN_INT_CONVERSION = YES; 290 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 291 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 292 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 293 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 294 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 295 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 296 | CLANG_WARN_STRICT_PROTOTYPES = YES; 297 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 298 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 299 | CLANG_WARN_UNREACHABLE_CODE = YES; 300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 301 | COPY_PHASE_STRIP = NO; 302 | DEBUG_INFORMATION_FORMAT = dwarf; 303 | ENABLE_STRICT_OBJC_MSGSEND = YES; 304 | ENABLE_TESTABILITY = YES; 305 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 306 | GCC_C_LANGUAGE_STANDARD = gnu17; 307 | GCC_DYNAMIC_NO_PIC = NO; 308 | GCC_NO_COMMON_BLOCKS = YES; 309 | GCC_OPTIMIZATION_LEVEL = 0; 310 | GCC_PREPROCESSOR_DEFINITIONS = ( 311 | "DEBUG=1", 312 | "$(inherited)", 313 | ); 314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 316 | GCC_WARN_UNDECLARED_SELECTOR = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 318 | GCC_WARN_UNUSED_FUNCTION = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | IPHONEOS_DEPLOYMENT_TARGET = 17.2; 321 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 322 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 323 | MTL_FAST_MATH = YES; 324 | ONLY_ACTIVE_ARCH = YES; 325 | SDKROOT = iphoneos; 326 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 327 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 328 | }; 329 | name = Debug; 330 | }; 331 | 7E1378522B360A1D00C83B78 /* Release */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 336 | CLANG_ANALYZER_NONNULL = YES; 337 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_ENABLE_OBJC_WEAK = YES; 342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 343 | CLANG_WARN_BOOL_CONVERSION = YES; 344 | CLANG_WARN_COMMA = YES; 345 | CLANG_WARN_CONSTANT_CONVERSION = YES; 346 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 348 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 349 | CLANG_WARN_EMPTY_BODY = YES; 350 | CLANG_WARN_ENUM_CONVERSION = YES; 351 | CLANG_WARN_INFINITE_RECURSION = YES; 352 | CLANG_WARN_INT_CONVERSION = YES; 353 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 354 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 355 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 356 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 357 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 359 | CLANG_WARN_STRICT_PROTOTYPES = YES; 360 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 361 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 362 | CLANG_WARN_UNREACHABLE_CODE = YES; 363 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 364 | COPY_PHASE_STRIP = NO; 365 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 366 | ENABLE_NS_ASSERTIONS = NO; 367 | ENABLE_STRICT_OBJC_MSGSEND = YES; 368 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 369 | GCC_C_LANGUAGE_STANDARD = gnu17; 370 | GCC_NO_COMMON_BLOCKS = YES; 371 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 372 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 373 | GCC_WARN_UNDECLARED_SELECTOR = YES; 374 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 375 | GCC_WARN_UNUSED_FUNCTION = YES; 376 | GCC_WARN_UNUSED_VARIABLE = YES; 377 | IPHONEOS_DEPLOYMENT_TARGET = 17.2; 378 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 379 | MTL_ENABLE_DEBUG_INFO = NO; 380 | MTL_FAST_MATH = YES; 381 | SDKROOT = iphoneos; 382 | SWIFT_COMPILATION_MODE = wholemodule; 383 | VALIDATE_PRODUCT = YES; 384 | }; 385 | name = Release; 386 | }; 387 | 7E1378542B360A1D00C83B78 /* Debug */ = { 388 | isa = XCBuildConfiguration; 389 | buildSettings = { 390 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 391 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 392 | CODE_SIGN_STYLE = Automatic; 393 | CURRENT_PROJECT_VERSION = 1; 394 | DEVELOPMENT_ASSET_PATHS = "\"testable-view-swiftui/Preview Content\""; 395 | DEVELOPMENT_TEAM = 83W6RLCTAG; 396 | ENABLE_PREVIEWS = YES; 397 | GENERATE_INFOPLIST_FILE = YES; 398 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 399 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 400 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 401 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 402 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 403 | LD_RUNPATH_SEARCH_PATHS = ( 404 | "$(inherited)", 405 | "@executable_path/Frameworks", 406 | ); 407 | MARKETING_VERSION = 1.0; 408 | PRODUCT_BUNDLE_IDENTIFIER = "com.mobile.testable-view-swiftui"; 409 | PRODUCT_NAME = "$(TARGET_NAME)"; 410 | SWIFT_EMIT_LOC_STRINGS = YES; 411 | SWIFT_VERSION = 5.0; 412 | TARGETED_DEVICE_FAMILY = "1,2"; 413 | }; 414 | name = Debug; 415 | }; 416 | 7E1378552B360A1D00C83B78 /* Release */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 420 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 421 | CODE_SIGN_STYLE = Automatic; 422 | CURRENT_PROJECT_VERSION = 1; 423 | DEVELOPMENT_ASSET_PATHS = "\"testable-view-swiftui/Preview Content\""; 424 | DEVELOPMENT_TEAM = 83W6RLCTAG; 425 | ENABLE_PREVIEWS = YES; 426 | GENERATE_INFOPLIST_FILE = YES; 427 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 428 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 429 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 430 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 431 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 432 | LD_RUNPATH_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "@executable_path/Frameworks", 435 | ); 436 | MARKETING_VERSION = 1.0; 437 | PRODUCT_BUNDLE_IDENTIFIER = "com.mobile.testable-view-swiftui"; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_EMIT_LOC_STRINGS = YES; 440 | SWIFT_VERSION = 5.0; 441 | TARGETED_DEVICE_FAMILY = "1,2"; 442 | }; 443 | name = Release; 444 | }; 445 | 7E1378572B360A1D00C83B78 /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 449 | BUNDLE_LOADER = "$(TEST_HOST)"; 450 | CODE_SIGN_STYLE = Automatic; 451 | CURRENT_PROJECT_VERSION = 1; 452 | DEVELOPMENT_TEAM = 83W6RLCTAG; 453 | GENERATE_INFOPLIST_FILE = YES; 454 | IPHONEOS_DEPLOYMENT_TARGET = 17.2; 455 | MARKETING_VERSION = 1.0; 456 | PRODUCT_BUNDLE_IDENTIFIER = "com.mobile.testable-view-swiftuiTests"; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | SWIFT_EMIT_LOC_STRINGS = NO; 459 | SWIFT_VERSION = 5.0; 460 | TARGETED_DEVICE_FAMILY = "1,2"; 461 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/testable-view-swiftui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/testable-view-swiftui"; 462 | }; 463 | name = Debug; 464 | }; 465 | 7E1378582B360A1D00C83B78 /* Release */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 469 | BUNDLE_LOADER = "$(TEST_HOST)"; 470 | CODE_SIGN_STYLE = Automatic; 471 | CURRENT_PROJECT_VERSION = 1; 472 | DEVELOPMENT_TEAM = 83W6RLCTAG; 473 | GENERATE_INFOPLIST_FILE = YES; 474 | IPHONEOS_DEPLOYMENT_TARGET = 17.2; 475 | MARKETING_VERSION = 1.0; 476 | PRODUCT_BUNDLE_IDENTIFIER = "com.mobile.testable-view-swiftuiTests"; 477 | PRODUCT_NAME = "$(TARGET_NAME)"; 478 | SWIFT_EMIT_LOC_STRINGS = NO; 479 | SWIFT_VERSION = 5.0; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/testable-view-swiftui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/testable-view-swiftui"; 482 | }; 483 | name = Release; 484 | }; 485 | /* End XCBuildConfiguration section */ 486 | 487 | /* Begin XCConfigurationList section */ 488 | 7E13782A2B360A1B00C83B78 /* Build configuration list for PBXProject "testable-view-swiftui" */ = { 489 | isa = XCConfigurationList; 490 | buildConfigurations = ( 491 | 7E1378512B360A1D00C83B78 /* Debug */, 492 | 7E1378522B360A1D00C83B78 /* Release */, 493 | ); 494 | defaultConfigurationIsVisible = 0; 495 | defaultConfigurationName = Release; 496 | }; 497 | 7E1378532B360A1D00C83B78 /* Build configuration list for PBXNativeTarget "testable-view-swiftui" */ = { 498 | isa = XCConfigurationList; 499 | buildConfigurations = ( 500 | 7E1378542B360A1D00C83B78 /* Debug */, 501 | 7E1378552B360A1D00C83B78 /* Release */, 502 | ); 503 | defaultConfigurationIsVisible = 0; 504 | defaultConfigurationName = Release; 505 | }; 506 | 7E1378562B360A1D00C83B78 /* Build configuration list for PBXNativeTarget "testable-view-swiftuiTests" */ = { 507 | isa = XCConfigurationList; 508 | buildConfigurations = ( 509 | 7E1378572B360A1D00C83B78 /* Debug */, 510 | 7E1378582B360A1D00C83B78 /* Release */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | /* End XCConfigurationList section */ 516 | 517 | /* Begin XCRemoteSwiftPackageReference section */ 518 | 7E13788F2B38C21B00C83B78 /* XCRemoteSwiftPackageReference "ViewInspector" */ = { 519 | isa = XCRemoteSwiftPackageReference; 520 | repositoryURL = "https://github.com/nalexn/ViewInspector.git"; 521 | requirement = { 522 | kind = upToNextMajorVersion; 523 | minimumVersion = 0.9.9; 524 | }; 525 | }; 526 | /* End XCRemoteSwiftPackageReference section */ 527 | 528 | /* Begin XCSwiftPackageProductDependency section */ 529 | 7E1378902B38C21B00C83B78 /* ViewInspector */ = { 530 | isa = XCSwiftPackageProductDependency; 531 | package = 7E13788F2B38C21B00C83B78 /* XCRemoteSwiftPackageReference "ViewInspector" */; 532 | productName = ViewInspector; 533 | }; 534 | /* End XCSwiftPackageProductDependency section */ 535 | }; 536 | rootObject = 7E1378272B360A1B00C83B78 /* Project object */; 537 | } 538 | --------------------------------------------------------------------------------