@@ -3,21 +3,19 @@ Prefer Value Types (Structs) When Possible
33Value 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