Skip to content

Commit 374aee2

Browse files
authored
Add support for Xcode 14 (#33)
* Fix compilation * Fix compilation warnings * Update development tools * Remove workarounds from example app that are fixed in iOS16 * Run unit tests with Xcode14 * Reorder modifiers as iOS16 propergates refreshable context to a screen presented with sheet * Ignore lint warning for rule AllPublicDeclarationsHaveDocumentation in example app * Update simulator device name format
1 parent 866588b commit 374aee2

File tree

12 files changed

+29
-22
lines changed

12 files changed

+29
-22
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
matrix:
1818
xcode_version:
1919
- 13.3
20+
- 14.0.1
2021
env:
2122
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode_version }}.app
2223
steps:
@@ -34,7 +35,7 @@ jobs:
3435
name: Validation
3536
runs-on: macos-12
3637
env:
37-
DEVELOPER_DIR: /Applications/Xcode_13.3.app
38+
DEVELOPER_DIR: /Applications/Xcode_14.0.1.app
3839
steps:
3940
- uses: actions/checkout@v2
4041
- name: Validate lint

Examples/App.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@
267267
CODE_SIGN_IDENTITY = "-";
268268
CODE_SIGN_STYLE = Manual;
269269
INFOPLIST_FILE = "App/Info-iOS.plist";
270-
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
270+
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
271271
LD_RUNPATH_SEARCH_PATHS = (
272272
"$(inherited)",
273273
"@executable_path/Frameworks",
@@ -336,7 +336,7 @@
336336
CODE_SIGN_IDENTITY = "-";
337337
CODE_SIGN_STYLE = Manual;
338338
INFOPLIST_FILE = "App/Info-iOS.plist";
339-
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
339+
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
340340
LD_RUNPATH_SEARCH_PATHS = (
341341
"$(inherited)",
342342
"@executable_path/Frameworks",

Examples/Packages/CrossPlatform/Sources/ExampleTodo/Screens.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct TodoListScreen: View {
3434

3535
#if os(iOS)
3636
.listStyle(.insetGrouped)
37-
.buttonStyle(.borderless)
37+
.buttonStyle(.borderless)
3838
#elseif !os(tvOS)
3939
.buttonStyle(.borderless)
4040
#endif

Examples/Packages/iOS/Sources/ExampleMovieDB/Screens/MoviesScreen.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ struct MoviesScreen: View {
6363
text: $searchQuery,
6464
placement: .navigationBarDrawer(displayMode: .always)
6565
)
66-
.onSubmit(of: .search) { [$isShowingSearchScreen] in
67-
$isShowingSearchScreen.wrappedValue = true
66+
.onSubmit(of: .search) {
67+
isShowingSearchScreen = true
6868
}
6969
.task(id: loader.filter) {
7070
await loader.refresh()
7171
}
72-
.refreshable { [context] in
72+
.refreshable {
7373
// NB: Implicitly capturing `self` causes memory leak with `refreshable`,
7474
// and also capturing `loader` makes refresh doesn't work, so here reads
7575
// `MovieLoader` via context.

Examples/Packages/iOS/Sources/ExampleMovieDB/Screens/SearchScreen.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ struct SearchScreen: View {
3535
}
3636
.navigationTitle("Search Results")
3737
.listStyle(.insetGrouped)
38+
.refreshable {
39+
await context.refresh(SearchMoviesAtom())
40+
}
3841
.sheet(item: $selectedMovie) { movie in
3942
DetailScreen(movie: movie)
4043
}
41-
.refreshable { [context] in
42-
await context.refresh(SearchMoviesAtom())
43-
}
4444
}
4545
}
4646

Examples/project.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ targets:
4646
templates:
4747
- App
4848
platform: iOS
49-
deploymentTarget: 15.0
49+
deploymentTarget: 16.0
5050
dependencies:
5151
- package: iOSApp
5252
sources:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ SWIFT_FILE_PATHS = Package.swift Sources Tests Examples
44
TEST_PLATFORM_IOS = iOS Simulator,name=iPhone 13 Pro
55
TEST_PLATFORM_MACOS = macOS
66
TEST_PLATFORM_TVOS = tvOS Simulator,name=Apple TV 4K (at 1080p) (2nd generation)
7-
TEST_PLATFORM_WATCHOS = watchOS Simulator,name=Apple Watch Series 7 - 45mm
7+
TEST_PLATFORM_WATCHOS = watchOS Simulator,name=Apple Watch Series 7 (45mm)
88

99
.PHONY: proj
1010
proj:

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ let package = Package(
2727
if ProcessInfo.processInfo.environment["SWIFTUI_ATOM_PROPERTIES_DEVELOPMENT"] != nil {
2828
package.dependencies.append(contentsOf: [
2929
.package(url: "https://github.com/apple/swift-docc-plugin", exact: "1.0.0"),
30-
.package(url: "https://github.com/apple/swift-format.git", exact: "0.50600.1"),
30+
.package(url: "https://github.com/apple/swift-format.git", exact: "0.50700.0"),
3131
.package(url: "https://github.com/yonaskolb/XcodeGen.git", exact: "2.32.0"),
3232
])
3333
}

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ struct BooksView: View {
948948
}
949949
}
950950
.searchable(text: searchQuery)
951-
.refreshable { [context] in // NB: Unfortunately, SwiftUI has a memory leak when capturing `self` implicitly inside a `refreshable` modifier.
951+
.refreshable {
952952
// refresh
953953
await context.refresh(FetchBooksAtom())
954954
}
@@ -1437,7 +1437,7 @@ In the above example, the initial state of the atom is retrieved from UserDefaul
14371437

14381438
### Dealing with Known SwiftUI Bugs
14391439

1440-
#### In iOS14, modal presentation causes assertionFailure when dismissing it
1440+
#### Modal presentation causes assertionFailure when dismissing it (Fixed in iOS15)
14411441

14421442
<details><summary><code>💡 Click to expand workaround</code></summary>
14431443

@@ -1464,10 +1464,10 @@ struct RootView: View {
14641464

14651465
</details>
14661466

1467-
Unfortunately, SwiftUI has a bug in iOS14 where the `EnvironmentValue` is removed from a screen presented with `.sheet` just before dismissing it. Since this library is designed based on `EnvironmentValue`, this bug end up triggering the friendly `assertionFailure` that is added so that developers can easily aware of forgotten `AtomRoot` implementation.
1467+
Unfortunately, SwiftUI has a bug in iOS14 or lower where the `EnvironmentValue` is removed from a screen presented with `.sheet` just before dismissing it. Since this library is designed based on `EnvironmentValue`, this bug end up triggering the friendly `assertionFailure` that is added so that developers can easily aware of forgotten `AtomRoot` implementation.
14681468
As a workaround, `AtomRelay` has the ability to explicitly inherit the internal store through `AtomViewContext` from the parent view.
14691469

1470-
#### Some SwiftUI modifiers cause memory leak
1470+
#### Some SwiftUI modifiers cause memory leak (Fixed in iOS16)
14711471

14721472
<details><summary><code>💡 Click to expand workaround</code></summary>
14731473

@@ -1495,7 +1495,7 @@ var isShowingSearchScreen = false
14951495

14961496
</details>
14971497

1498-
Some modifiers in SwiftUI seem to cause an internal memory leak if it captures `self` implicitly or explicitly. To avoid that bug, make sure that `self` is not captured when using those modifiers.
1498+
In iOS 15 or lower, some modifiers in SwiftUI seem to cause an internal memory leak if it captures `self` implicitly or explicitly. To avoid that bug, make sure that `self` is not captured when using those modifiers.
14991499
Below are the list of modifiers I found that cause memory leaks:
15001500

15011501
- [`refreshable(action:)`](https://developer.apple.com/documentation/SwiftUI/View/refreshable(action:))

Sources/Atoms/Context/AtomTestContext.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ public struct AtomTestContext: AtomWatchableContext {
216216
public func watch<Node: ObservableObjectAtom>(_ atom: Node) -> Node.Loader.Value {
217217
state.store.watch(atom, container: state.container) { [weak state] in
218218
// Ensures that the observable object is updated before notifying updates.
219-
RunLoop.current.perform {
219+
RunLoop.current.perform { [weak state] in
220220
state?.notifyUpdate()
221221
}
222222
}
@@ -260,7 +260,6 @@ public struct AtomTestContext: AtomWatchableContext {
260260
}
261261

262262
private extension AtomTestContext {
263-
@MainActor
264263
final class State {
265264
private let _store = Store()
266265
private let _container = SubscriptionContainer()
@@ -278,6 +277,7 @@ private extension AtomTestContext {
278277
StoreContext(_store, overrides: overrides)
279278
}
280279

280+
@MainActor
281281
var container: SubscriptionContainer.Wrapper {
282282
_container.wrapper(location: location)
283283
}

0 commit comments

Comments
 (0)