Dive into the world of programming languages used for app development.

All subtopics

Post

Replies

Boosts

Views

Activity

Getting error while creating identity from certificate and key
I am trying to create identity from certificate and private key which are in base64 format. I am getting error - Unable to create identity one time I get the error - Failed to add certificate and private key to keychain: -26276 My Xcode is 15.3 and macOS is Sonoma 14.5 func loadIdentity(certificate: String, privateKey: String) -> SecIdentity? { guard let certData = Data(base64Encoded: certificate) else { print("Unable to encode certificate base64") return nil } guard let cert = SecCertificateCreateWithData(nil, certData as CFData) else { print("Unable to create certificate") return nil } let certAddQuery: [NSString: Any] = [ kSecClass: kSecClassCertificate, kSecValueRef: cert, kSecAttrLabel: "myCertificate" ] var status = SecItemAdd(certAddQuery as CFDictionary, nil) if status != errSecSuccess && status != errSecDuplicateItem { print("Failed to add certificate to keychain: \(status)") return nil } guard let keyData = Data(base64Encoded: privateKey) else { print("Unable to encode private key base64") return nil } let keyDict: [NSString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: 2048, kSecReturnPersistentRef: true ] var error: Unmanaged<CFError>? guard let privateKeyData = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, &error) else { print("Unable to create private key") return nil } let keyAddQuery: [NSString: Any] = [ kSecClass: kSecClassKey, kSecValueRef: privateKeyData, kSecAttrLabel: "myKey", kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked ] status = SecItemAdd(keyAddQuery as CFDictionary, nil) if status != errSecSuccess && status != errSecDuplicateItem { print("Failed to add private key to keychain: \(status)") return nil } let identityQuery: [NSString: Any] = [ kSecClass: kSecClassIdentity, kSecReturnRef: true, kSecAttrLabel: "myCertificate", kSecMatchItemList: [cert, privateKeyData] ] var identity: CFTypeRef? status = SecItemCopyMatching(identityQuery as CFDictionary, &identity) guard status == errSecSuccess else { print("Unable to create identity") return nil } return (identity as! SecIdentity) }
0
0
143
Aug ’24
how to clear a TextField when it is bound to a Swiftdata object that doesn't allow optionals
Say you have a SwiftData object that doesn't allow optionals: @Model class MySet: Identifiable { var id: UUID var weight: Int var reps: Int var isCompleted: Bool var exercise: Exercise Then you get from your MySet data a list of these MySets and append them into a State: @State var sets: [MySet] if let newSets = exercise.sets { //unwrapping the passed exercises sets if (!newSets.isEmpty) { //we passed actual sets in so set them to our set sets = newSets } And you use that State array in a ForEach and bind the Textfield directly to the data like so: ForEach($sets){ $set in TextField("\(set.weight)", value: $set.weight, formatter: NumberFormatter()) .keyboardType(.decimalPad) TextField("\(set.reps)", value: $set.reps,formatter: NumberFormatter()) .keyboardType(.decimalPad) } This will bind whatever is written into the TextField directly to the SwiftData object which is a problem because say you have 50 written and you want to change it to 60 you need to be able to clear the 50 to write the 60 and since the SwiftData object doesn't allow nil it will allow you to remove the 0 but not the 5. Is there anyway to remedy this without having the swiftData object allow optionals for example catching the clearing of the TextField and making it 0 instead of nil when its cleared?
0
0
220
Aug ’24
Task Isolation Inheritance and SwiftUI
This post discusses a subtlety in Swift concurrency, and specifically how it relates to SwiftUI, that I regularly see confusing folks. I decided to write it up here so that I can link to it rather than explain it repeatedly. If you have a question or a comment, start a new thread and I’ll respond there. Put it in the App & System Services > Processes & Concurrency topic area and tag it with both Swift and Concurrency. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Task Isolation Inheritance By default, tasks inherit their actor isolation from the surrounding code. This is a common source of confusion. My goal here is to explain why it happens, why it can cause problems, and how to resolve those problems. Imagine you have a main actor class like this: @MainActor class MyClass { var counter: Int = 0 func start() { Task { print("will sleep") doSomeCPUIntensiveWork() print("did sleep") } } } In this example the class is a model object of some form, but it could be an @Observable type, a SwiftUI view, a UIKit view controller, and so on. The key thing is that the type itself is isolated to the main actor. Remember that Swift code inherits its isolation from the surrounding code (in compiler author speak this is called the lexical context). So the fact that MyClass is annotated with @MainActor means that both counter and start() are isolated to the main actor. IMPORTANT This model is what allows the compiler to detect concurrency problems at compile time. I’ve found that, whenever I’m confused by Swift concurrency, it helps to ask myself “What does the compiler know?” Folks look at this code and think “But I’ve added a Task, and that means that doSomeCPUIntensiveWork() will run on a secondary thread!” That is not true. There are a couple of easy ways to prove this to yourself: Actually run the code. If you put this code into an app, you’ll find that your app’s UI is unresponsive for the duration of the doSomeCPUIntensiveWork(). Indeed, you can test this example for yourself, as explained below in Example Context. Access a value that’s isolated to the main actor. For example, insert this doSomeCPUIntensiveWork(): self.counter += 1 doSomeCPUIntensiveWork() The compiler doesn’t complain about this access to counter — a main-actor-isolated value — from this context, which tell you that this code will run on the main thread. So, what’s going on? The task is running on the main actor because of a form of isolation inheritance. The mechanics of that are complex, something I’ll explained in the The Gory Details section below. For the moment, however, the key thing to note is that starting a task in this way — using Task.init(…) — causes the task to inherit actor isolation from the surrounding code. In this case the surrounding code is the start() method, which is isolated to the main actor because it’s part of MyClass, and thus the code ends up calling doSomeCPUIntensiveWork() on the main thread. So, how do you prevent this? There are many different ways, but the two most obvious are: Replace Task.init(…) with Task.detached(…): func start() { Task.detached() { print("will sleep") doSomeCPUIntensiveWork() print("did sleep") } } And how does that work? Again, see the The Gory Details section below. Move the code to a non-isolated method: func start() { Task { print("will sleep") await self.myDoSomeCPUIntensiveWork() print("did sleep") } } nonisolated func myDoSomeCPUIntensiveWork() async { doSomeCPUIntensiveWork() } In both cases you can prove to yourself that this has done the right thing: Add code to access counter from the non-isolated context and observe the complaints from the compiler. SwiftUI While my “What does the compiler know?” thought experiment is super helpful, sometimes it’s not easy understand that. Folks are often caught out by the way that the SwiftUI View protocol works. We’ve fixed this problem in Xcode 16, but that change has brought more confusion. In Xcode 15 and earlier the View protocol was defined like this: public protocol View { … @ViewBuilder @MainActor var body: Self.Body { get } } Only the body property is annotated with @MainActor. The view as a whole is not. Consider this view: struct CounterViewOK: View { @State var counter: Int = 0 var body: some View { VStack { Text("\(counter)") Button("Increment") { Task { counter += 1 } } } } } This compiles because the task inherits the main actor isolation from body. But if you make a seemingly trivial change, the compiler complains: struct CounterViewNG: View { @State var counter: Int = 0 var body: some View { VStack { Text("\(counter)") Button("Increment") { increment() } } } func increment() { Task { counter += 1 // ^ Capture of 'self' with non-sendable type 'CounterViewNG' in a `@Sendable` closure } } } That’s because the increment() method is not isolated to the main actor, and thus neither is the task. The compiler thinks you’re trying to pass an instance of the view between contexts, and rightly complains. In contrast, in Xcode 16 (currently in beta) the View protocol looks ilke this: @MainActor @preconcurrency public protocol View { … @ViewBuilder @MainActor @preconcurrency var body: Self.Body { get } } The entire View is now isolated to the main actor. This makes everything easier to understand. Both of the examples above work. Specifically, CounterViewNG works because the task inherits main actor isolation via the increment() > CounterViewNG > View chain. Of course, everything is a trade-off. More of your views are now running on the main actor, which can trigger the CPU intensive work issue that I described above. Other Options When I crafted the doSomeCPUIntensiveWork() example above, I avoided mentioning SwiftUI. There was a specific reason for that: When working with a UI framework, it’s best to avoid doing significant work in your UI types. This is true in SwiftUI, but it’s also true in UIKit and AppKit. Indeed, doing all your app’s work in your view controllers is called the massive view controller anti-pattern. So, if you’re find yourself doing significant work in your UI types, consider some alternatives. You have lots of options: The simplest option is to move the code into an async function. But you might also want to add an abstraction layer. Swift has lots of good options for that (structs, enums, classes, actors). You can also define a new global actor. The best option depends on your specific situation. If you’re looking for further advice, there’s no shortage of it out there on the ’net (-: The Gory Details To understand the difference between Task.init(…) and Task.detached(…), you have to look at their declarations. This is easy to do from Xcode — just command-click on the init or the detached — but that’s misleading. The difference is keyed off a underscore-prefixed attribute and, for better or worse, Xcode won’t show you those. To see the actual difference you have have to open the Swift interface file. Within any given SDK the relevant file is usr/lib/swift/_Concurrency.swiftmodule/arm64e-apple-macos.swiftinterface. Here’s what you’ll see in the macOS SDK within Xcode 16.0b4: @discardableResult @_alwaysEmitIntoClient public init( priority: TaskPriority? = nil, @_inheritActorContext @_implicitSelfCapture operation: __owned @escaping @isolated(any) @Sendable () async -> Success ) {…} @discardableResult @_alwaysEmitIntoClient public static func detached( priority: TaskPriority? = nil, operation: __owned @escaping @isolated(any) @Sendable () async -> Success ) -> Task<Success, Failure> {…} Note I’ve edited this significantly to make things easier to read. The critical difference is the use of @_inheritActorContext in the Task.init(…) case. This tells the compiler that the closure argument should inherit its isolation from the surrounding code. This attribute is underscored, and thus there’s no Swift Evolution proposal for it, but there is some limited documentation. Example Context To run the example in context, create a new command-line tool project, rename main.swift to start.swift, and insert MyClass into this scaffolding: import Foundation @MainActor class MyClass { … code above … } func doSomeCPUIntensiveWork() { sleep(5) } @main struct Main { static func main() { Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in print("tick") } let m = MyClass() m.start() withExtendedLifetime(m) { RunLoop.current.run() } } } In this context: doSomeCPUIntensiveWork() uses the sleep system call to hog the current thread for 5 seconds. The timer tick helps illustrate the unresponsive main thread. It’s also need to ensure that the run loop continues to run indefinitely. More Reading There is a lot of good information available about Swift concurrency. My favourite resources include: The Swift Programming Language > Concurrency Migrating to Swift 6 The Avoid hangs by keeping the main thread free from non-UI work section of Improving app responsiveness WWDC 2023 Session 10248 Analyze hangs with Instruments, especially the section starting at 31:42. Swift Evolution proposals SE-0431 @isolated(any) Function Types which covers another subtle issue with tasks Matt Massicotte blog at https://www.massicotte.org Revision History 2024-08-05 Added the Other Options section. Added some more links to the More Reading section. Made other minor editorial changes. 2024-08-01 First posted.
0
0
845
Aug ’24
swift: documentation for proper import name?
This bites me a lot. I'm looking at the documentation for, say, UNUserNotificationCenter. And NOWHWERE but NOWHERE do I see anything that says, "hey, on platform *** you should import YYY to use this class." Am I just not looking in the right place in Apple documentation to find this? Surely, somewhere at the top level of documentation, it must tell you want the proper package to import is, per platform?
1
0
279
Aug ’24
Porting Thread & Delegate Code to Swift 6 Using Tasks
Hello, I have a lot of apps and I am currently trying to port them over to Swift 6. I thought that this process should be relatively simple but I have to admit that I have a lot of trouble to understand how the Concurrency system works. Let's start with some code that shows how I am currently working when it comes to asynchronous work in my apps: I have a Model that is marked with @Observable. Inside this model, a Controller is hosted. The Controller has its own ControllerDelegate. The Model has a search function. Inside this function a lot of IO stuff is executed. This can take a lot of time. Because of this fact, I am doing this in a separate Thread. I all is put together, it looks a little bit like this: @main struct OldExampleApp : App { @State private var model = Model() var body: some Scene { WindowGroup { ContentView() .environment(self.model) } } } struct ContentView: View { @Environment(Model.self) private var model var body: some View { if self.model.isSearching { ProgressView() } else { Button("Start") { self.model.search() } } } } protocol ControllerDelegate : AnyObject { func controllerDidStart() func controllerDidEnd() } class Controller { weak var delegate: ControllerDelegate? func search() { let thread = Thread { DispatchQueue.main.async { self.delegate?.controllerDidStart() } // Do some very complex stuff here. Let's use sleep to simulate this. Thread.sleep(forTimeInterval: 2.0) DispatchQueue.main.async { self.delegate?.controllerDidEnd() } } thread.start() } } @Observable class Model { private(set) var isSearching = false var controller = Controller() init() { self.controller.delegate = self } func search() { self.controller.search() } } extension Model : ControllerDelegate { func controllerDidStart() { self.isSearching = true } func controllerDidEnd() { self.isSearching = false } } This works perfectly fine and by that I mean: The task is run in the background. The main thread is not blocked. The main window can be dragged around, no beach ball cursor etc. Now comes the Swift 6 part: I want to merge the Model and Controller into one class (Model). I still want the Model to be Observable. I want to run arbitrary code in the Model. This means that the code is not necessarily a prime candidate for await like getting data from a web server etc. The main thread should not be blocked, so the main window should still be movable while the app calculates data in the background. I have this example: struct ContentView: View { @Environment(Model.self) private var model var body: some View { if self.model.controller.isSearching { ProgressView() } else { Button("Search") { Task { await self.model.controller.heavyWork() } } } } } @Observable final class Model : Sendable { @MainActor var controller = AsyncController() init() { } } @Observable @MainActor class AsyncController { private(set) var isSearching = false public func heavyWork() async { self.isSearching = true Swift.print(Date.now) let i = self.slowFibonacci(34) Swift.print(i) Swift.print(Date.now) self.isSearching = false } func slowFibonacci(_ n: Int) -> Int { if n <= 1 { return n } let x = slowFibonacci(n - 1) let y = slowFibonacci(n - 2) return x + y } } I come from a C# background and my expectation is that when I use a Task with await, the main thread is not blocked and the Code that is called inside the Task runs in the background. It seems like the function is run in the background, but the UI is not updated. Because I set the isSearching flag to true, I would expect that the app would display the ProgressView - but it does not. I changed the code to this: public func heavyWork() async { self.isSearching = true Swift.print(Date.now) let i = await self.slowFibonacci(20) Swift.print(i) Swift.print(Date.now) self.isSearching = false } func slowFibonacci(_ n: Int) async -> Int { let task = Task { () -> Int in if n <= 1 { return n } let x = await slowFibonacci(n - 1) let y = await slowFibonacci(n - 2) return x + y } return await task.value } This seems to work - but is this correct? I have this pattern implemented in one of my apps and there the main thread is blocked when the code is run. So I think it all comes down to this: Is it possible, to run a arbitrary code block (without an await in it) in a Task, that can be awaited so the main thread is not blocked? The class (or actor?) that contains the function that is called via await should be Observable. Or should I simply keep my Swift 5 code and move on? :D Regards, Sascha
3
0
436
Jul ’24
Regression in Concurrent Task Execution on macOS 15 Beta: Seeking Clarification
Developer Community, I've noticed a significant change in concurrent task execution behavior when testing on macOS 15 beta 4 &amp;amp; Xcode 16 Beta 4 compared to previous versions. Tasks that previously ran concurrently now appear to execute sequentially, impacting performance and potentially affecting apps relying on concurrent execution. To illustrate this, I've created a simple toy example: import SwiftUI struct ContentView: View { @State private var results: [String] = [] var body: some View { VStack { Button("Run Concurrent Tasks") { results.removeAll() runTasks() } ForEach(results, id: \.self) { result in Text(result) } } } func runTasks() { Task { async let task1 = countingTask(name: "Task 1", target: 1000) async let task2 = countingTask(name: "Task 2", target: 5000) async let task3 = countingTask(name: "Task 3", target: 1500) let allResults = await [task1, task2, task3] results = allResults } } func countingTask(name: String, target: Int) async -&amp;gt; String { print("\(name) started") var count = 0 for _ in 0..&amp;lt;target { count += 1 } print("\(name) finished. Count: \(count)") return "\(name) completed. Count: \(count)" } } Observed behavior (macOS 15 Beta 4 &amp;amp; Xcode 16 Beta 4): Tasks appear to execute sequentially: Task 1 started Task 1 finished. Count: 1000 Task 2 started Task 2 finished. Count: 5000 Task 3 started Task 3 finished. Count: 1500 Expected behavior: Tasks start almost simultaneously and finish based on their workload: Task 1 started Task 2 started Task 3 started Task 1 finished. Count: 1000 Task 3 finished. Count: 1500 Task 2 finished. Count: 5000 Observed behavior in macOS 15 Beta: The profile reveals that the tasks are executing sequentially. This is evidenced by each task starting only after the previous one has completed.
3
0
479
Jul ’24
TestIDs on iOS concatenated - React Native
Hey guys, so I have a problem regarding the testIDs on my react native that is reproducible only on iOS DOM meaning that I set the ids individually on the elements on a page but the problem is that somehow the ids are concatenated between them and inherits all the ids under the parent. As you can see and imagine in the accessibility inspector, this is what my DOM looks like. I want to point out that the problem does not reproduce on Android, only on iOS. Can somebody help me with this and tell me if there is a way to disable this concatenation? What's relevant to tell you it's the fact that I need each element to have an unique ID for browserstack automated tests. But as you can see in the image an element contains all IDs concatenated for some reason. And here is the code for the page with this issue
0
0
364
Jul ’24
"Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races"
I'm currently in the process of migrating to Swift 6. A lot of my code triggers the warning from the title. Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races. I depend on the .task/.refreshable modifiers and buttons that trigger asynchronous work that cannot be done on the Main Actor since it takes way to long. The below code demonstrates the problem. Some comments explain my problems further. I read a lot of articles and documentations but couldn't find an answer to such a seemingly simple error struct ContentView: View { // Marking Senable as suggested by the warning causes different warning for @State @State private var authorizationStatus: MusicAuthorization.Status = .notDetermined // Sole purpose to trigger the errors var body: some View { VStack { Text("Hello, world!") Button("Some button") { Task { await doingSomeAsyncWork() // WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races } } } .task { // Or refreshable I believe both behave the same await doingSomeAsyncWork() // WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races } } // Marking @MainActor is not an option since some of these functions might be running for more than 10 seconds // Tried marking func as nonisolated but that obviously had no effect func doingSomeAsyncWork() async { authorizationStatus = await MusicAuthorization.request() // Just to have a easy asynchronous function. Without some async code in here, the errors disappear } } Thank you
1
0
889
Jul ’24
Swift playgrounds - (issue with code setup)
hi im fairly new to coding.. about a month, just so u know.. 😇 I am going through the tasks in (Swift Playgrounds) and I am currently in (Learning to code 2) the chapter is (Random gems everywhere) and I tried every possible solution to complete it, but to no avail! any suggestions, comments, or corrections or tips, would be greatly appreciated! I will attach some screenshots for a reference of what I'm trying to accomplish..
0
0
294
Jul ’24
macOS 15 + Xcode 16 Beta 4 Problem with .task {} and async function
Hi everyone, when I was doing some testing on macOS 15 + Xcode 16 Beta 4 I noticed that my app's performance took a significant hit. A simple task that previously was completed within 15 seconds or less now took about a minute to complete. I came to the conclusion that the only plausible cause could be the way .task {} and asynchronous functions are handled. Starting several .task{} and calling async functions from within using macOS 14.5 and Xcode 15.4 results in following log output: task1 started task3 started task2 started task4 started --&gt; task2 ended --&gt; task3 ended --&gt; task4 ended --&gt; task1 ended` Running the same code on macOS 15.0 + Xcode 16 Beta 4 will result in the following log output: task1 started --&gt; task1 ended task2 started --&gt; task2 ended task3 started --&gt; task3 ended task4 started --&gt; task4 ended In the first example the code is executed in 'parallel'. All tasks are started and doing there respective work. In second example a task is started and we are waiting for it to complete before the other tasks are started. I could start to rewrite my code to get the results I desire, however I'm wondering if this is a bug in regards to macOS 15 + Xcode 16 Beta 4 and the way .task {} and asynchronous functions are handled. The output is quite different after all. What's your take on this? If you want to try it out for yourself you can use the following sample code: import SwiftUI struct ContentView: View { func func1() async -&gt; Int { print("task1 started") var myInt: Int = 0 while myInt &lt; 999999999 { myInt += 1 } print(" --&gt; task1 ended") return 1 } func func2() async -&gt; Int { print("task2 started") var myInt: Int = 0 while myInt &lt; 999999 { myInt += 1 } print(" --&gt; task2 ended") return 2 } func func3() async -&gt; Int { print("task3 started") var myInt: Int = 0 while myInt &lt; 999999 { myInt += 1 } print(" --&gt; task3 ended") return 3 } func func4() async -&gt; Int { print("task4 started") var myInt: Int = 0 while myInt &lt; 999999999 { myInt += 1 } print(" --&gt; task4 ended") return 4 } var body: some View { VStack { Text("Hello, world!") } .task { await func1() } .task { await func2() } .task { await func3() } .task { await func4() } } } #Preview { ContentView() }
1
0
483
Jul ’24
Main actor-isolated instance method 'locationManagerDidChangeAuthorization' cannot be used to satisfy nonisolated protocol requirement
I'm going through the migration to Swift 6 and I am running up with a few things. I have two view controllers which conform to the CLLocationManagerDelegate protocol. Both methods of the delegate have the same issue in my code. Below is an example of the warning received. Main actor-isolated instance method 'locationManagerDidChangeAuthorization' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode
4
0
1k
Jul ’24
Implementing a Main Actor Protocol That’s Not @MainActor
When adopting Swift 6, it’s common to encounter frameworks and libraries that haven’t been audited for sendability. I get pinged about this regularly, so I decided to write up my take on it. If you have questions or comments, put them in a new thread. Use the Programming Languages > Swift subtopic and tag it with Concurrency; that way I’ll be sure to I see it. IMPORTANT This is covered really well in the official documentation. Specifically, look at the Under-Specified Protocol section of Migrating to Swift 6. I wrote this up most as an excuse to get it all straight in my head. Oh, one last thing: This is all based on the Swift 6 compiler in Xcode 16.0b4. Swift concurrency is evolving rapidly, so you might see different results in newer or older compilers. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Implementing a Main Actor Protocol That’s Not @MainActor Imagine you’re using the WaffleOMatic framework. It has a WaffleVarnisher class like this: class WaffleVarnisher { weak var delegate: Delegate? protocol Delegate: AnyObject { func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) } } class Waffle { var isGlossy: Bool = false } You are absolutely sure that the varnisher calls its delegate on the main thread, but the framework hasn’t been audited for sendability [1]. When you adopt it in a main-actor class, you hit this problem: @MainActor class WaffleState: WaffleVarnisher.Delegate { var lastWaffle: Waffle? = nil func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) { // ^ Main actor-isolated instance method 'varnished(_:didVarnish:)' // cannot be used to satisfy nonisolated protocol requirement self.lastWaffle = waffle } } That error has three fix-its: Add 'nonisolated' to 'varnished(_:didVarnish:)' to make this instance method not isolated to the actor Add '@preconcurrency' to the 'Delegate' conformance to defer isolation checking to run time Mark the protocol requirement 'varnished(_:didVarnish:)' 'async' to allow actor-isolated conformances I’ll discuss each in turn, albeit out of order. [1] If it had, WaffleVarnisher.Delegate would be annotated with the @MainActor attribute. Fix-it 3: Apply async If you choose fix-it 3, Mark the protocol requirement 'varnished(_:didVarnish:)' 'async' to allow actor-isolated conformances, the compiler changes the varnished(_:didVarnish:) to be async: class WaffleVarnisher { … protocol Delegate: AnyObject { func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) async } } This is a non-starter because one of our assumptions is that you can’t change the WaffleOMatic framework [1]. [1] If you could, you’d add the @MainActor attribute to WaffleVarnisher.Delegate and this whole problem goes away. Fix-it 1: Apply non-isolated If you choose fix-it 1, Add 'nonisolated' to 'varnished(_:didVarnish:)' to make this instance method not isolated to the actor, you get this: @MainActor class WaffleState1: WaffleVarnisher.Delegate { var lastWaffle: Waffle? = nil nonisolated func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) { self.lastWaffle = waffle // ^ Main actor-isolated property 'lastWaffle' can not be mutated from a non-isolated context } } It’s fixed the original error but now you have a new one. The protocol method is non-isolated, so it can’t access the main-actor-only lastWaffle property. You can work around this with assumeIsolated(…), but this yields another error: @MainActor class WaffleState1: WaffleVarnisher.Delegate { var lastWaffle: Waffle? = nil nonisolated func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) { // A MainActor.assumeIsolated { // B self.lastWaffle = waffle // ^ Sending 'waffle' risks causing data races } } } You’re now passing the waffle object from a non-isolated context (A) to the main-actor-isolated context (B), and you can’t do that because that object is not sendable [1]. You can’t make Waffle sendable because you don’t own the WaffleOMatic framework. That leaves two options. The first is to extract sendable properties from waffle and pass them between the isolation contexts. For example, imagine that you only care about the isGlossy property of the last waffle. In that case, you might write code like this: @MainActor class WaffleState1: WaffleVarnisher.Delegate { var wasLastWaffleGlossy: Bool? = nil nonisolated func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) { let wasGlossy = waffle.isGlossy MainActor.assumeIsolated { self.wasLastWaffleGlossy = wasGlossy } } } Problem solved! The other option is to disable concurrency checking. There are a variety of ways you might do that. For example, you might apply @preconcurrency on the import, or use an @unchecked Sendable box to transport the waffle, or whatever. I’m not going to discuss these options in detail here because they run counter to the overall goal of Swift concurrency. [1] Of course both of these contexts are the same!, that is, the main actor context. However, the Swift compiler doesn’t know that. Remember that the goal of Swift concurrency is to have your concurrency checked at compile time, so it’s critical to view errors like this from the perspective of the compiler. Fix-it 2: Apply preconcurrency If you choose fix-it 2, Add '@preconcurrency' to the 'Delegate' conformance to defer isolation checking to run time, you get this [1]: @MainActor class WaffleState3: @preconcurrency WaffleVarnisher.Delegate { var lastWaffle: Waffle? = nil func varnisher(_ varnisher: WaffleVarnisher, didVarnish waffle: Waffle) { self.lastWaffle = waffle } } This is the best solution to this problem IMO. In this context the @preconcurrency attribute [2] does two things: It tells the compiler that it can assume that the WaffleVarnisher.Delegate methods are called in the appropriate isolation context for this type. In that case that means the main actor. It inserts runtime checks to these delegate methods to verify that assumption. The key advantage of fix-it 2 over fix-it 1 is that compiler knows that the delegate callback is isolated to the main actor, and so: It doesn’t complain when you access main-actor-isolated constructs like lastWaffle. It knows that you’re not smuggling waffles across state lines isolation contexts. [1] Or it will, once we fix the fix-it (r. 132570262) (-: [2] The @preconcurrency attribute has very different different meanings depending on the context! Synchronous Results The advantages of fix-it 2 increase when the delegate protocol includes methods that return a result synchronously. Imagine that the WaffleVarnisher.Delegate protocol has a second callback like this: class WaffleVarnisher { … protocol Delegate: AnyObject { func varnisher(_ varnisher: WaffleVarnisher, shouldMakeGlossy waffle: Waffle) -> Bool … } } The fix-it 2 approach lets you implement that delegate using state that’s isolated to the main actor: @MainActor class WaffleState: @preconcurrency WaffleVarnisher.Delegate { var lastWaffle: Waffle? = nil func varnisher(_ varnisher: WaffleVarnisher, shouldMakeGlossy waffle: Waffle) -> Bool { return !(self.lastWaffle?.isGlossy ?? false) } … } In this case it’s possible to solve this problem with the fix-it 1 approach as well, but the code is uglier: nonisolated func varnisher(_ varnisher: WaffleVarnisher, shouldMakeGlossy waffle: Waffle) -> Bool { return MainActor.assumeIsolated { return !(self.lastWaffle?.isGlossy ?? false) } } However, that doesn’t always work. If the delegate method returns a non-sendable type, this approach will fail with a does not conform to the 'Sendable' protocol error.
0
0
389
Jul ’24
Unable to import ObjC interface from a package in a public ObjC file in a framework
Problem Statement: Unable to import .h file from an ObjC SPM to a .h file in an ObjC file in a framework with mix of ObjC and Swift code The issue is: in order to support access of ObjC file in Swift code in a framework we need to use umbrella header (in place of bridging header). Once the file is imported in Umbrella header and made public it will no longer allow import of .h file from package in its interface Project Structure: a. Package: ObjCPackage ObjCPackage |- Package.swift |- ObjCPackage MathsUtilities.h (class interface) MathsUtilities.m (class implementation) NiceLogs.h (protocol) b. Project: ObjCSwiftFramework ObjCSwiftFramework |- ObjCSwiftFramework.h (umbrella header) |- Calculation.h (objc class interface) |- Calculation.m (objc class implementation) |- SwiftCalci.swift (swift class) Details: #import <ObjCSwiftFramework/Calculation.h> added in ObjCSwiftFramework.h as Calculation has to be used in SwiftCalci Calculation.h marked as public in target membership in Xcode so that it can be added in umbrella header ObjCSwiftFramework.h #import "NiceLogs.h" in Calculation.h gives error Here is a small sample which I created to demonstrate the problem: ObjCSwiftFramework
1
0
400
May ’24
@Observable class not compatible with Codable?
So any time I create a class that's both @Observable and Codable, e.g. @Observable class GameLocationManager : Codable { I get a warning in the macro expansion code: @ObservationIgnored private let _$observationRegistrar = Observation.ObservationRegistrar() Immutable property will not be decoded because it is declared with an initial value which cannot be overwritten. I've been ignoring them for now, but there are at least a half a dozen of them now in my (relatively small) codebase, and I'd like to find a solution (ideally one that doesn't require me to write init(decoder:) for every @Observable class in my project...), especially since I'm not sure what the actual consequences of ignoring this might be.
1
0
326
Jul ’24
NumberFormat formatting exceeds 16 decimal places exception
Example1: let num = NSDecimalNumber(string: "0.123456789012345678909") let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.usesGroupingSeparator = true formatter.maximumFractionDigits = 25 formatter.minimumFractionDigits = 25 formatter.minimumIntegerDigits = 1 let str = formatter.string(from: num) ?? "" print(str) output "0.1234567890123460000000000" Example2: let num = NSDecimalNumber(string: "12323.123456789012345678909") let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.usesGroupingSeparator = true formatter.maximumFractionDigits = 25 formatter.minimumFractionDigits = 25 formatter.minimumIntegerDigits = 1 let str = formatter.string(from: num) ?? "" print(str) output "12,323.1234567890000000000000000" How to correctly format the contents of the above two inputs?
1
0
264
Jul ’24
Weird crashes when accessing Swift Array
For some time now Xcode has been downloading crash reports from users of my app about crashes related to arrays. One of them looks like this: ... Code Type: ARM-64 Parent Process: launchd [1] User ID: 501 Date/Time: 2024-07-18 14:59:40.4375 +0800 OS Version: macOS 15.0 (24A5289h) ... Crashed Thread: 0 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001045048b8 Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5 Terminating Process: exc handler [1771] Thread 0 Crashed: 0 MyApp 0x00000001045048b8 specialized Collection.map<A>(_:) + 596 1 MyApp 0x00000001045011e4 MyViewController.validateToolbarButtons() + 648 (MyViewController.swift:742) ... The relevant code looks like this: class MyViewController { func validateToolbarButtons() { let indexes = tableView.clickedRow == -1 || tableView.selectedRowIndexes.contains(tableView.clickedRow) ? tableView.selectedRowIndexes : IndexSet(integer: tableView.clickedRow) let items = indexes.map({ myArray[$0] }) ... } } The second crash looks like this: ... Code Type: X86-64 (Native) Parent Process: launchd [1] User ID: 502 Date/Time: 2024-07-15 15:53:35.2229 -0400 OS Version: macOS 15.0 (24A5289h) ... Crashed Thread: 0 Exception Type: EXC_BAD_INSTRUCTION (SIGILL) Exception Codes: 0x0000000000000001, 0x0000000000000000 Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4 Terminating Process: exc handler [13244] Thread 0 Crashed: 0 libswiftCore.dylib 0x00007ff812904fc0 _assertionFailure(_:_:flags:) + 288 1 MyApp 0x0000000101a31e04 specialized _ArrayBuffer._getElementSlowPath(_:) + 516 2 MyApp 0x00000001019d04eb MyObject.myProperty.setter + 203 (MyObject.swift:706) 3 MyApp 0x000000010192f66e MyViewController.controlTextDidChange(_:) + 190 (MyViewController.swift:166) ... And the relevant code looks like this: class MyObject { var myProperty: [MyObject] { get { ... } set { let items = newValue.map({ $0.id }) ... } } } What could cause such crashes? Could they be caused by anything other than concurrent access from multiple threads (which I'm quite sure is not the case here, as I only access these arrays from the main thread)?
13
0
733
Jul ’24
[SwiftUI] When to use closures vs equals for variable assignment?
Hi, I'm new to swift but have experience with coding in general. Following the app dev training tutorial, came across this line of code: var wrapper: ErrorWrapper { ErrorWrapper(error: someVal) } My question is, why not just do this... var wrapper: ErrorWrapper = ErrorWrapper(error: someVal) Is it a conventions thing or is there some purpose, code seems to work either way. My understanding of closures is that they are just lambda functions, so in the first codeblock, all it's doing is calling a function that returns the instantiated ErrorWrapper object. Why not just assign the variable to it?
1
0
281
Jul ’24
OTA-updates for objective-c application
Hello! I have an application written in Objective-c/C++ and I would like it to have support for OTA updates. I implemented the logic through two executable files, one of which was responsible for launching and updating the first, but this option did not pass Apple's review. Could you tell me how this functionality can be implemented and so that it meets the requirements of the App Store.
1
0
278
Jul ’24
Objective-C++ confuses two private classes with the same name
I think I found a bug in the Objective-C++ compiler, linker, or runtime. Here’s the scenario: We have a macOS app written in Swift. To control hardware from a 3rd party manufacturer, we use a couple SDKs provided by the manufacturer. The SDKs use dynamically loaded libraries and the interface is defined in C++ headers. To bridge between our Swift code and the C++ APIs we have a private Cocoapod that wraps the 3rd party interface with Objective-C++ classes. The two SDKs each provide an interface for discovering attached devices using a callback class that the programmer provides. By accident we named both callback implementations DiscoveryCallback, but this was not a compiler error because neither class was publicly declared, and each was defined in the .mm file where it was used. However, the problem we’re seeing is this: We want to discover Videohub devices, so we register a new instance of DiscoveryCallback (defined in the same .mm file as this code) with the Videohub SDK. A Videohub device is connected and the SDK calls a method on our callback. Surprise! The callback we registered in step 1 was actually the one intended for Decklink devices, defined in a completely different .mm file. This violates all sorts of assumptions and our app quickly crashes. The funny thing is, the two implementations of DiscoveryCallback have completely different method names. The Videohub SDK is supposed to be calling NewVideohubDevice, yet somehow it successfully calls DeckLinkDeviceArrived on an instance of a class it shouldn’t even know about. So the compiler has checked that our intended DiscoveryCallback matches the protocol that the SDK expects, but at runtime the compiled code instantiates a completely different implementation of DiscoveryCallback and somehow doesn’t immediately fail; we still call a method on it that doesn’t even share a name with the intended target. I imagine at this point the method names are long forgotten and are just pointers in a table. I don’t know if this is a bug in the compiler, the Objective-C++ runtime, or if this is just “working as designed” undefined behavior that I should have avoided by not giving two private classes the same name. I know it’s possible to use a private API simply by redeclaring it in my own code, and this seems related to that, but I feel like the compiler or linker should have warned me that I had two implementations of the same class, or if that is not an error, then the runtime should have instantiated the class that was privately defined in the same source file where it was used. Obviously I can’t share our entire project; I’d like to provide some sample code that replicates the issue, but I don’t have time to do that right now. I’m posting this to see if other developers have had a similar experience.
2
1
453
Jul ’24