Skip to content

Commit 246b89e

Browse files
Update MigrationGuideSwift6.swift
1 parent 4494b66 commit 246b89e

1 file changed

Lines changed: 60 additions & 21 deletions

File tree

SwiftUIExamples/MigrationGuideSwift6.swift

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,19 @@ Prefer Value Types (Structs) When Possible
33
Value types are copied when passed around, reducing the risk of shared mutable state.
44

55
// MARK: Example 1
6-
/*class HomeViewController {
7-
8-
private var loadingView = UIView() // Error here `Main actor-isolated default value in a nonisolated context`
6+
class HomeViewControllerLegacy {
97

8+
private var loadingView = UIView() // Error here `Main actor-isolated default value in a nonisolated context`
109
var hasLaunched = false
1110

1211
@MainActor
1312
func home() {
1413
self.hasLaunched = true
1514
}
1615
}
17-
*/
18-
// To solve it - initializing the view at declaration time, so you can safely create it in viewDidLoad() which runs on the main thread.
1916

20-
class HomeViewController: UIViewController {
17+
// To solve it - initializing the view at declaration time, so you can safely create it in viewDidLoad() which runs on the main thread.
18+
class HomeViewControllerNew: UIViewController {
2119
private var loadingView: UIView!
2220

2321
override func viewDidLoad() {
@@ -29,15 +27,14 @@ class HomeViewController: UIViewController {
2927
}
3028

3129
// MARK: Example 2 Passing closure as a 'sending' parameter risks causing data races
32-
/*
33-
class Logger {
30+
class LoggerLegacy {
3431
var logs: [String] = []
3532

3633
func log(_ message: String) {
3734
logs.append(message)
3835
}
3936
}
40-
struct Worker {
37+
struct WorkerLegacy {
4138
let logger: Logger
4239

4340
func doWork() {
@@ -46,21 +43,21 @@ struct Worker {
4643
}
4744
}
4845
}
49-
*/
46+
5047
//-> If you know there is no data race in your codebase & want to skip data race use @preconcurrency
5148
@preconcurrency
52-
class Logger {
49+
class LoggerNew {
5350
var logs: [String] = []
5451

5552
func log(_ message: String) {
5653
logs.append(message)
5754
}
5855
}
5956

60-
extension Logger: @unchecked Sendable {}
57+
extension LoggerNew: @unchecked Sendable {}
6158

62-
struct Worker {
63-
let logger: Logger
59+
struct WorkerNew {
60+
let logger: LoggerNew
6461

6562
func doWork() {
6663
Task {
@@ -70,8 +67,8 @@ struct Worker {
7067
}
7168

7269
// MARK: Example # Trying to access heightConstraint from background thread.
73-
/*
74-
class ProfileViewController: UIViewController {
70+
71+
class ProfileViewControllerLegacy: UIViewController {
7572
var heightConstraint: NSLayoutConstraint!
7673

7774
override func viewDidLoad() {
@@ -85,9 +82,9 @@ class ProfileViewController: UIViewController {
8582
}
8683
}
8784
}
88-
*/
85+
8986
// Solution ->
90-
class ProfileViewController: UIViewController {
87+
class ProfileViewControllerNew: UIViewController {
9188
var heightConstraint: NSLayoutConstraint!
9289

9390
override func viewDidLoad() {
@@ -110,7 +107,7 @@ class CartView {
110107
@IBOutlet var label: UILabel!
111108

112109
// Error version
113-
func addItem() {
110+
func addItemLegacy() {
114111
DispatchQueue.global().async {
115112
// Error here # Main actor-isolated property 'text' can not be mutated from a Sendable closure
116113
self.label.text = "Updated"
@@ -127,7 +124,7 @@ class CartView {
127124
}
128125

129126
// MARK: Example #5 Accessing Non-Sendable Types Across Threads
130-
class SongClass {
127+
class SongClassLegacy {
131128
var data: String = ""
132129

133130
func update() {
@@ -139,7 +136,7 @@ class SongClass {
139136
}
140137
}
141138

142-
actor SongClassFixed {
139+
actor SongClassNew {
143140
private var data = ""
144141

145142
func append(_ value: String) {
@@ -151,5 +148,47 @@ actor SongClassFixed {
151148
}
152149
}
153150

151+
// MARK: Example #6 sendable examples
152+
final class SteelFactoryLegacy {
153+
// Closure to be called after background work
154+
var onUpdate: (() -> Void)?
155+
156+
func performWork() {
157+
DispatchQueue.global().async { [weak self] in
158+
// Simulate background work
159+
sleep(1)
160+
// Warning Capture of 'self' with non-sendable type 'SteelFactoryLegacy?' in a '@Sendable' closure
161+
self?.onUpdate?()
162+
163+
}
164+
}
165+
}
166+
167+
168+
final class SteelFactoryNew {
169+
// Closure that can be safely called from concurrent contexts
170+
var onUpdate: (@Sendable () -> Void)?
171+
172+
func performWork() {
173+
DispatchQueue.global().async { [onUpdate] in
174+
// Simulate background work
175+
sleep(1)
154176

177+
// Safely call the closure
178+
onUpdate?()
179+
}
180+
}
181+
}
182+
// Usage -
183+
class CompanyOffice {
184+
185+
func getInfo() {
186+
let manager = SteelFactoryNew()
187+
manager.onUpdate = { [message = "Update received!"] in
188+
print(message)
189+
}
190+
manager.performWork()
191+
192+
}
193+
}
155194

0 commit comments

Comments
 (0)