Reputation: 5347
All the libraries I have come across that provide Swift concurrency functionality either depend on an Objective-C library or are wrappers around the C based GCD. (iOS and OS X)
I'm just wondering if anyone knows of a pure Swift concurrency library? No dependencies. Or if not how might we go about making one?
Upvotes: 4
Views: 541
Reputation: 34175
Swift Concurrency
[Concurrency vs Parallelism]
[Sync vs Async]
Swift has built-in support for writing asynchronous and parallel code in a structured way.
It is a kind of from Swift v5.5 iOS v15 and v13 backward compatibility
solves:
try/catch
mechanism)High level structure:
await/async
markers for recognising async block and run it. You are able to use withCheckedThrowingContinuation
and withCheckedContinuation
inside callback to support await/async
Actor
)Task
- create a concurrent environment in which await/async
is allowed, it is stared immediately after creation, can be prioritized duting creation and can be canceled, has it's own lifetime as a result - current state. Task.init(priority:operation:)
creates unstructured concurrency(doesn't have a parent task)
Task Group
- allow to run parallel(more dynamic then await async let
) tasks and all off them done - task group is finished. When you use TaskGroup.addTask
or await async let
creates Structured concurrency because it has explicit parent-child relationship between task and taskGroupActor
] - share mutable referance_type data between tasks
in a concurrent environment which prevents Data raceExample:
func runImageTask() {
let imageSaver = ImageSaver()
Task.init {
do {
let url = URL(string: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_dark_color_272x92dp.png")!
guard let image = try await self.downloadImage(from: url) else { return }
try await imageSaver.storeImage(image)
guard let transformedImage = try await self.transformImage(image) else { return }
try await imageSaver.storeImage(transformedImage)
self.showImage(transformedImage)
} catch {
print("error:\(error)")
}
}
}
func downloadImage(from url: URL) async throws -> UIImage? {
let (data, response) = try await URLSession.shared.data(from: url)
return UIImage(data: data)
}
func transformImage(_ image: UIImage) async throws -> UIImage? {
return try await withCheckedThrowingContinuation { continuation in
DispatchQueue.global().async {
UIGraphicsBeginImageContext(image.size)
image.draw(at: CGPoint.zero)
guard let context = UIGraphicsGetCurrentContext() else {
continuation.resume(with: .failure(NSError(domain: "context is nil", code: 1)))
return
}
context.setStrokeColor(UIColor.green.cgColor)
context.setLineWidth(5)
context.addEllipse(in: CGRect(x: 50, y: 50, width: 50, height: 50))
context.drawPath(using: .stroke)
let transformedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
continuation.resume(with: .success(transformedImage))
}
}
}
func showImage(_ image: UIImage) {
self.imageView.image = image
}
class ImageSaver: NSObject {
var continuation: CheckedContinuation<Void, Error>? = nil
func storeImage(_ image: UIImage) async throws {
return try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation
UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveCompleted), nil)
}
}
@objc func saveCompleted(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
let result: Result<(), Error>
if let error = error {
result = .failure(error)
} else {
result = .success(())
}
self.continuation?.resume(with: result)
}
}
Upvotes: 0
Reputation: 9196
As of Swift 5.5, Swift now supports concurrency with built-in language features such as async/await
, Tasks, TaskGroups, Actors and Structured Concurrency.
Upvotes: 0
Reputation: 131408
The Swift language doesn't have constructs to support concurrency yet. Rumor has it that those are going to be added to a future version of the language, but in the meantime, I don't think you can do this without OS support.
GCD makes for fairly clean concurrent solutions in Swift, since GCD blocks are Swift closures. It's not platform-indpendent, however. (At least not outside the Apple ecosystem.)
I guess you could write a concurrency library that would run on all POSIX-compliant OS's by using POSIX, but Windows isn't really POSIX-compliant, so that might not be a perfect solution either.
In Swift 3 the GCD interface has been cleaned up and made much more "Swifty". Now there is a Dispatch class, that has class methods to do the things that used to use global functions.
Upvotes: 4
Reputation: 1066
You can create a simple abstraction of queue-based dispatching like this:
protocol OperationQueue {
var suspended: Bool { get set }
var operationCount: Int { get }
func addOperationWithBlock(block: () -> Void)
func cancelAllOperations()
func waitUntilAllOperationsAreFinished()
}
Then, on OS X (or any other Apple platform), you could use GCD directly:
extension NSOperationQueue: OperationQueue { }
And on all other systems, you could create your own implementations:
class POSIXOperationQueue: OperationQueue { /* implementation with pthread */ }
class Win32OperationQueue: OperationQueue { /* implementation with Win32 API */ }
Upvotes: 0