1

We have received an external dependency framework from one of our partners, and their latest version (v2) of the framework only exposes Swift async interfaces. We were in the middle of integrating the previous version (v1) of the framework, which does not utilize Swift async, when the new version (v2) was released. We encountered an issue with v1, and their support team recommended switching to the latest version (v2), mentioning that v1 may contain a bug. So now we need to somehow integrate the code that looks like

let data = try await storage?.data(forKey: key)

in to the code that expect

let data = storage?.data(forKey: key)
return data 

which wouldn't be a problem if there was only swift code but we also have a fair bit of objc code that is using the same framework and the code

NSData *data = [storage storedDataForKey:key];
return data

becomes something like

NSData *data = [storage storedDataForKey:key completionHandler:^(NSData* data) {
   // do something here and then call completion
}

it has a knock off effect and requires changes of quite a lot of code. Considering all we need now is just to check the v2 of the framework work as expected and has no bug I am wondering if there is a simpler solution that could wrap async interfaces of the v2 and let us test the framework.

  • 1
    "Considering all we need now is just to check the v2 of the framework work as expected" For just that purpose, you can put a `DispatchSemaphore` before each callback-based API, `.wait()` it after calling registering the callback. It'll wait until you `.signal()` from inside the callback. Note: this will bring everything to a slow, synchronous grinding halt, which you probably expect – Alexander Jun 08 '23 at 20:55
  • Apple explicitly tells us that semaphores are unsafe in conjunction with Swift concurrency. https://developer.apple.com/videos/play/wwdc2021/10254?time=1558. The function in question should to be, itself, an `async` method. – Rob Jun 09 '23 at 00:40
  • Bottom line, if v2 of this API is using asynchronous API, then you really should refactor your Objective-C code to follow completion handler patterns, as painful as that seems at this point (or start to refactor that code to Swift using Swift concurrency, which is likely even more painful). ☹️ That having been said, if (and only if) that Objective-C code is off the main thread, you can entertain semaphores within that Objective-C code (though that has its own risks), but it's impossible to advise you without a more complete example. – Rob Jun 09 '23 at 00:52
  • You know, unless the OP acknowledges that they know it’s a really bad idea and understand the risks and problems it entails, I think it is very good to outline the problems/risks and why the practice is discouraged. – Rob Jun 09 '23 at 14:56
  • Use semaphore https://stackoverflow.com/questions/70962534/swift-await-async-how-to-wait-synchronously-for-an-async-task-to-complete **BUT** as said (here in comments and in answers comments), it is **NOT RECOMMENDED**, and you might find issues (after it's not recommended as unsafe, and blocking threads) for your proof of concept, but later, you'll need anyway to convert your sync code to async one... – Larme Jun 09 '23 at 17:12
  • Thanks all. I ended up using modified version of this code https://gist.github.com/sainecy/4366a1b99c7317fac63bfeb19d1cfab2 that has been posted https://stackoverflow.com/questions/70962534/swift-await-async-how-to-wait-synchronously-for-an-async-task-to-complete. That was enough to test the framework – TiredMagicalCoder Jun 10 '23 at 16:42

0 Answers0