Concurrency

RSS for tag

Concurrency is the notion of multiple things happening at the same time.

Pinned Posts

Posts under Concurrency tag

89 Posts
Sort by:
Post not yet marked as solved
6 Replies
4.2k Views
The C compiler accepts the option '-std=c11' and responds by defining the define token '__STDC_VERSION__' = 201112 which thereby claims C11 support. Additionally, it DOES NOT define '__STDC_NO_THREADS__' and therefore the include headers <threads.h> and <stdatomic.h> should exist but they dont. The compiler is promising C11 threads, condition variables, ... support but does NOT provide it. This is NOT a link time problem, it is a compile time issue.
Posted
by
Post not yet marked as solved
2 Replies
2.7k Views
I have the following method in NSOperationQueue category:- (void)addOperation:(NSOperation *)op withDelayInNanoseconds:(int64_t)nanoseconds { int64_t delay = (self.operationCount * nanoseconds); int64_t timeInterval = (int64_t)(nanoseconds + delay); int64_t boundTimeInterval = timeInterval >= 0 ? timeInterval : 0; __weak typeof(self) weakSelf = self; NSLog(@"%@ addOperation: %@ intoQueue: %@ withOperationDelayInNanoseconds: %@ boundTimeInterval: %@. operationCount: %@", weakSelf.debugDescription, op, weakSelf.underlyingQueue, @(nanoseconds), @(boundTimeInterval), @(weakSelf.operationCount)); //uderlyingQueue could be nil. //maybe just add operation in queue? //https://github.com/Tricertops/GrandSwiftDispatch/issues/1 //maybe the best why is to remove such a queue :/ if (weakSelf.underlyingQueue == nil) { NSLog(@"%@ underlyingQueue is %@", weakSelf.debugDescription, weakSelf.underlyingQueue); } dispatch_queue_t queue = weakSelf.underlyingQueue ?: dispatch_queue_create("com.myproject.concurrency", NULL); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, boundTimeInterval), queue, ^{ [weakSelf addOperation:op]; }); }It may not work ( not sure how it works. )But in this code I encountered self.unerlyingQueue value nil due to documentation.So, I put adding operation in dispatch_after block and it is fires after delay.This example adds delay only before adding operation. It don't add delay gap between two operations with desired interval.Now I try to figure out how to do it.Subclass from NSOperation.@interface MyProjectDelayedOperation : NSOperation @property (assign, nonatomic, readwrite) NSInteger beforeDelayInSeconds; @property (assign, nonatomic, readwrite) NSInteger afterDelayInSeconds; @end @interface MyProjectDelayedOperation () @property (strong, readwrite) NSOperation *operation; @property (readwrite, getter=isCancelled) BOOL cancelled; @property (readwrite, getter=isExecuting) BOOL executing; @property (readwrite, getter=isFinished) BOOL finished; //@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below //@property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0); @property (readonly, getter=isReady) BOOL ready; @end static const void *observerContextIsCancelled; static const void *observerContextIsFinished; @implementation MyProjectDelayedOperation - (instancetype)initWithOperation:(NSOperation *)operation { if (self = [super init]) { self.operation = operation; [self.operation addObserver:self forKeyPath:@"isCancelled" options:0 context:observerContextIsCancelled]; [self.operation addObserver:self forKeyPath:@"isFinished" options:0 context:observerContextIsFinished]; } return self; } - (void)start { // wait before start for seconds. double delayInSeconds = self.beforeDelayInSeconds; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); __weak __typeof(self)weakSelf = self; dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [weakSelf willChangeValueForKey:@"isExecuting"]; weakSelf.executing = YES && !weakSelf.cancelled; [weakSelf didChangeValueForKey:@"isExecuting"]; if (self.executing && !self.cancelled) { [weakSelf.operation start]; } }); } // subscipt on operation values. - (void)cancel { [self willChangeValueForKey:@"isCancelled"]; self.cancelled = YES; [self didChangeValueForKey:@"isCancelled"]; if (!self.operation.cancelled) { [self.operation cancel]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ((object == self.operation) && (context == observerContextIsCancelled)) { [self cancel]; } else if ((object == self.operation) && (context == observerContextIsFinished)){ [self finished]; } } - (void)finished { // should wait for state "done" double delayInSeconds = self.afterDelayInSeconds; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); __weak __typeof(self)weakSelf = self; dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [weakSelf willChangeValueForKey:@"isExecuting"]; [weakSelf willChangeValueForKey:@"isFinished"]; weakSelf.executing = NO; weakSelf.finished = YES; [weakSelf didChangeValueForKey:@"isFinished"]; [weakSelf didChangeValueForKey:@"isExecuting"]; }); } @endIt wraps operation and adds intervals before start and after finish.It listens underlying operation events isCancelled and isFinished to react on them and to fire delayed operation finish.Not sure how to add before and after delays properly.Of course, this may work with queues maximum concurrent operations value equal one. ( Serial queue )
Posted
by
Post marked as solved
12 Replies
8.1k Views
Hi,Why this piece of code works?let queue = DispatchQueue(label: "queue_label", attributes: .concurrent) queue.sync { queue.sync { print("wokrs!") } }shouldn't be a deadlock here?Or maybe "attributes: .concurrent" makes .sync and .async always be an "async"?Thanks! 🙂
Posted
by
Post not yet marked as solved
7 Replies
4.4k Views
For some simulation work-loads I have, I would like to use the system to its full potential and therefore use both P and E cores. Splitting the work-load into individual tasks is not easily possible (the threads communicate with each other and run in semi-lockstep). I can allocate smaller portions of the domain to the E cores (and iteratively adjust this so they take the same amount of time as the P cores). But in order for this to work well, I need to ensure that a given thread (with its associated workload) is bound to the right type of core: *either* the performance (doing larger chunks of the domain) or the efficiency (doing smaller chunks of the domain) cores. What's the best way to do this? So far, I don't think thread-to-core affinity has been something that was choosable in macOS. The documentation mentioned the QoS classes, but which class(es) (or relative priorities) would I pick? c pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0); The existing classifications don't really map well, the work is user-initiated (i.e. they launched a console application), but not a GUI program. Would I use 4 threads with QOS_CLASS_UTILITY and 4 with QOS_CLASS_BACKGROUND? Would I just use UTILITY with relative priority for performance vs. efficiency cores?
Posted
by
Post not yet marked as solved
1 Replies
2.5k Views
How does one add Codable conformance to a class that needs to be isolated to the MainActor? For example, the following code gives compiler errors: @MainActor final class MyClass: Codable { var value: Int enum CodingKeys: String, CodingKey { case value } init(from decoder: Decoder) throws { // <-- Compiler error: Initializer 'init(from:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Decodable' let data = try decoder.container(keyedBy: CodingKeys.self) self.value = try data.decode(Int.self, forKey: .value) } func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Encodable' var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } I'm definitely struggling to get my head around actors and @MainActor at the moment!
Posted
by
Post not yet marked as solved
3 Replies
2.0k Views
Given that type UUID is a struct I thought it would be Sendable. But the compiler generates a warning: struct S: Sendable { var int: Int var id: UUID // &lt;-- Stored property 'id' of 'Sendable'-conforming struct 'S' has non-sendable type 'UUID' }
Posted
by
Post not yet marked as solved
5 Replies
2k Views
When marking the ViewController and the function with @MainActor, the assertion to check that the UI is updated on main thread fails. How do I guarantee that a function is run on Main Thread when using @MainActor? Example code: import UIKit @MainActor class ViewController: UIViewController {     let updateObject = UpdateObject()     override func viewDidLoad() {         super.viewDidLoad()                  updateObject.fetchSomeData { [weak self] _ in             self?.updateSomeUI()         }     }     @MainActor     func updateSomeUI() {         assert(Thread.isMainThread) // Assertion failed!     } } class UpdateObject {     func fetchSomeData(completion: @escaping (_ success: Bool) -> Void) {         DispatchQueue.global().async {             completion(true)         }     } } Even changing DispatchQueue.global().async to Task.detached does not work. Tested with Xcode 13.2.1 and Xcode 13.3 RC
Posted
by
Post not yet marked as solved
1 Replies
1.2k Views
Hey there, I have a problem running multiply tasks in parallel in a SwiftUI view. struct ModelsView: View { @StateObject var tasks = TasksViewModel() var body: some View { NavigationView{ ScrollView { ForEach(Array(zip(tasks.tasks.indices, tasks.tasks)), id: \.0) { task in NavigationLink(destination: ModelView()) { ModelPreviewView(model_name: "3dobject.usdz") .onAppear { if task.0 == tasks.tasks.count - 2 { Task { print(tasks.tasks.count) await tasks.fetch_tasks(count: 4) } } } } } }.navigationTitle("3D modelle") }.onAppear{ Task { await tasks.fetch_tasks(count: 5) await tasks.watch_for_new_tasks() } } } } In my view, I spawn a task as soon as the View Appears which, first, fetches 5 tasks from the database (this works fine), and then it starts watching for new tasks. In the Scroll View, right before the bottom is reached, I start loading new tasks. The problem is, the asynchronous function fetch_tasks(count: 4) only gets continued if the asynchronous function watch_for_new_tasks() stops blocking. actor TasksViewModel: ObservableObject { @MainActor @Published private(set) var tasks : [Tasks.Task] = [] private var last_fetched_id : String? = nil func fetch_tasks(count: UInt32) async { do { let tasks_data = try await RedisClient.shared.xrevrange(streamName: "tasks", end: last_fetched_id ?? "+" , start: "-", count: count) last_fetched_id = tasks_data.last?.id let fetched_tasks = tasks_data.compactMap { Tasks.Task(from: $0.data) } await MainActor.run { withAnimation(.easeInOut) { self.tasks.append(contentsOf: fetched_tasks) } } } catch { print("Error fetching taskss \(error)") } } func watch_for_new_tasks() async { while !Task.isCancelled { do { let tasks_data = try await RedisClient.shared.xread(streams: "tasks", ids: "$") let new_tasks = tasks_data.compactMap { Tasks.Task(from: $0.data) } await MainActor.run { for new_task in new_tasks.reversed() { withAnimation { self.tasks.insert(new_task, at: 0) } } } } catch { print(error) } } } ... } The asynchronous function watch_for_new_tasks() uses RedisClient.shared.xread(streams: "tasks", ids: "$") which blocks until at least one tasks is added to the Redis Stream. I tried running the watch_for_new_tasks() on a Task.detached tasks, but that also blocks. To be honest, I have no idea why this blocks, and I could use your guy's help if you could. Thank you in Advance, Michael
Posted
by
Post not yet marked as solved
2 Replies
1.1k Views
In my TestApp I run the following code, to calculate every pixel of a bitmap concurrently: private func generate() async {     for x in 0 ..< bitmap.width{         for y in 0 ..< bitmap.height{             let result = await Task.detached(priority:.userInitiated){                return iterate(x,y)             }.value             displayResult(result)         }     } } This works and does not give any warnings or runtime issues. After watching the WWDC talk "Visualize and optimize Swift concurrency" I used instruments to visualize the Tasks: The number of active tasks continuously raises until 2740 and stays constant at this value even after all 64000 pixels have been calculated and displayed. What am I doing wrong?
Posted
by
Post marked as solved
10 Replies
8.1k Views
This code can be compiled as command line tool for macOS. import Foundation @main struct App {     static var counter = 0     static func main() async throws {         print("Thread: \(Thread.current)")         let task1 = Task { @MainActor () -> Void in             print("Task1 before await Task.yield(): \(Thread.current)")             await Task.yield()             print("Task1 before await increaseCounter(): \(Thread.current)")             await increaseCounter()             print("Task1 after await increaseCounter(): \(Thread.current)")         }         let task2 = Task { @MainActor () -> Void in             print("Task2 before await Task.yield(): \(Thread.current)")             await Task.yield()             print("Task2 before await decreaseCounter(): \(Thread.current)")             await decreaseCounter()             print("Task2 after await decreaseCounter(): \(Thread.current)")         }         _ = await (task1.value, task2.value)         print("Final counter value: \(counter)")     }     static func increaseCounter() async {         for i in 0..<999 {             counter += 1             print("up step \(i), counter: \(counter), thread: \(Thread.current)")             await Task.yield()         }     }     static func decreaseCounter() async {         for i in 0..<999 {             counter -= 1             print("down step \(i), counter: \(counter), thread: \(Thread.current)")             await Task.yield()         }     } } My understanding is: static func main() async throws inherits MainActor async context, and should always run on the main thread (and it really seems that it does so) Task is initialized by the initializer, so it inherits the actor async context, so I would expect that will run on the main thread. Correct? Moreover, the closure for Task is annotated by @MainActor, so I would even more expect it will run on the main thread. I would expect that static func main() async throws inherits MainActor async context and will prevent data races, so the final counter value will always be zero. But it is not. Both task1 and task2 really start running on the main thread, however the async functions increaseCounter() and decreaseCounter() run on other threads than the main thread, so the Task does not prevent data races, while I would expect it. When I annotate increaseCounter() and decreaseCounter() by @MainActor then it works correctly, but this is what I do not want to do, I would expect that Task will do that. Can anyone explain, why this works as it does, please?
Posted
by
Post not yet marked as solved
1 Replies
2.4k Views
Hi, Xcode warns me that NSPersistentContainer, NSManagedObjectContext, NSPersistentHistoryTransaction and NSPersistentHistoryToken are non-Sendable types and therefore cannot cross actor boundaries. These warnings occur even when I use @preconcurrency import CoreData (only works with Xcode 14.0 Beta, in Xcode 13.4.1, it says '@preconcurrency' attribute on module 'CoreData' is unused) I understand that types in Core Data have yet to be marked as Sendable when it makes sense. Although NSPersistentHistoryTransaction, and NSPersistentHistoryToken are reference types, they should qualify to be marked as Sendable in the future since these are immutable types, am I right? NSPersistentContainer provides variables and methods like viewContext and newBackgroundContext(). It would make sense that this type is thread-safe. However, I'm not sure about it, especially regarding its loadPersistentStores(completionHandler:) method. Is NSPersistentContainer (and its subclass NSPersistentCloudKitContainer) thread-safe and should it be marked as Sendable in the future? The case of and NSManagedObjectContext confuses me the most. Indeed, it has both thread-safe methods like perform(_:) and thread-unsafe methods like save(). Still, it should be possible to cross actor boundaries. Would such a "partially thread-safe" type quality to be marked as Sendable? If not, how can it cross actor boundaries? The reason I'm asking these questions is that I have a CoreDataStack type. It has mutable variables, such as var lastHistoryToken: NSPersistentHistoryToken?, needs to perform work without blocking the main thread, such as writing the token to a file, has async methods, uses notification observers, and needs to be marked as Sendable to be used by other controllers running on different actors. Since this type is related to back-end work, I made it an Actor. This type exposes the persistent container, and a method to create new background threads. However, I need to explicitly annotate all methods using await context.perform { ... } as nonisolated in this actor. Not doing so causes a data race to be detected at runtime. Is this a bug, and is making a Core Data stack an Actor the proper way to do it or is there a better solution? Any help would be greatly appreciated. Thanks. Xcode Configuration Xcode 13.4.1, Xcode 14.0 beta 5 The Xcode project is configured with Other Swift Flags set to -Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks.
Posted
by
Post marked as solved
2 Replies
2.4k Views
Trying to implement a type that conforms to ASWebAuthenticationPresentationContextProviding. This is now causing errors with Xcode 14. With the following implementation:         final class PresentationContextProvider: NSObject, ASWebAuthenticationPresentationContextProviding {             func presentationAnchor(for session: ASWebAuthenticationSession) -&gt; ASPresentationAnchor {                 return ASPresentationAnchor()             }         } I get this compilation error: Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context So I can annotate the class or method with @MainActor, but then I get this warning: Main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement Is there a way to fix this?
Posted
by
Post not yet marked as solved
1 Replies
858 Views
For grins, I tried turning on strict concurrency checking in Xcode with one of our existing apps. We have a lot of work to do! But one thing that I ran across that it's not clear to me how to resolve (possibly because I haven't been following all of the concurrency changes super closely) is an apparent conflict between the UIContentView & UIContentConfiguration protocols (which have no concurrency annotations) and our current implementations (since UIView is marked @MainActor). I feel like there must be something obvious I'm missing. Stack Overflow post with example code: https://stackoverflow.com/questions/74214256/are-custom-uicontentview-uicontentconfiguration-implementations-incompatible-w
Posted
by
610
Post not yet marked as solved
2 Replies
1.9k Views
Hi, I'm trying to use async/await for KVO and it seems something is broken. For some reason, it doesn't go inside for in body when I'm changing the observed property. import Foundation import PlaygroundSupport class TestObj: NSObject {   @objc dynamic var count = 0 } let obj = TestObj() Task {   for await value in obj.publisher(for: \.count).values {     print(value)   } } Task.detached {   try? await Task.sleep(for: .microseconds(100))   obj.count += 1 } Task.detached {   try? await Task.sleep(for: .microseconds(200))   obj.count += 1 } PlaygroundPage.current.needsIndefiniteExecution = true Expected result: 0, 1, 2 Actual result: 0 Does anyone know what is wrong here?
Posted
by
Post marked as solved
4 Replies
863 Views
I'm running a simulation (SwiftUI app), which has 100 steps. I need each step to be executed in order. A first try was to dispatch with delay to schedule each second: for step in 0..<100 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 1.0) { // simulation code } } Very poor results as 100 running threads are too much load for the system. So I split in 2 stages: for bigStep in 0..<10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(bigStep) * 10.0 ) { for step in 0..<10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 1.0) { // simulation code } } } } It works much better, as now there are a max of 20 threads active (in fact I create more levels to limit to a max of 8 concurrent threads). It addition, it allows to interrupt the simulation before end. My questions: is it the appropriate pattern ? Would a timer be better ? Other options ?
Posted
by
Post not yet marked as solved
1 Replies
636 Views
I'm converting some Combine publishers to async using .values and trying to understand what happens when: A Publisher completes before emitting a value. Here is some example code: let response = client.fetch(query: query) .tryMap { /* map the data, or throw a mapping error if it doesn't map. */ } return Model() } .eraseToAnyPublisher() .values for try await result in response { return result } throw AsyncCombineError.finishedWithoutValue // my custom error What happens with .values if the publisher completes without emitting any values? It returns a type of AsyncThrowingSequence<Self> Will it throw? return? hang? or is this state impossible to happen? Thanks and please enlighten me if I am misunderstanding structured concurrency. This is new to me!
Posted
by
Post marked as solved
4 Replies
2.3k Views
Hi, we're seeing crashes in production for our app that's built using Xcode 14.3. As far as I can tell, this is related to structured concurrency and only users on iOS 15.0, 15.1 & 15.1.1 are affected. We had to revert back to using Xcode 14.2. There's also a post about this on swift.org forums (Structured concurrency bug in Xcode 14.3). We can't reproduce this on the simulator. Looks like there are several different types of crashes: BUG IN LIBDISPATCH: Lingering DISPATCH_WLH_ANON Crashed: com.apple.root.user-initiated-qos.cooperative 0 libdispatch.dylib 0x15d38 _dispatch_root_queue_drain + 244 1 libdispatch.dylib 0x165f8 _dispatch_worker_thread2 + 164 2 libsystem_pthread.dylib 0x10b8 _pthread_wqthread + 228 3 libsystem_pthread.dylib 0xe94 start_wqthread + 8 BUG IN CLIENT OF LIBDISPATCH: Voucher corruption Crashed: com.apple.root.user-initiated-qos.cooperative 0 libdispatch.dylib 0x3d924 _voucher_xref_dispose.cold.2 + 28 1 libdispatch.dylib 0x2a774 _voucher_xref_dispose + 268 2 libdispatch.dylib 0x6ed8 _dispatch_set_priority_and_voucher_slow + 272 3 libdispatch.dylib 0x16638 _dispatch_worker_thread2 + 228 4 libsystem_pthread.dylib 0x10b8 _pthread_wqthread + 228 5 libsystem_pthread.dylib 0xe94 start_wqthread + 8 API MISUSE: Voucher over-release Crashed: com.apple.root.user-initiated-qos.cooperative 0 libdispatch.dylib 0x6f38 _dispatch_set_priority_and_voucher_slow + 368 1 libdispatch.dylib 0x16638 _dispatch_worker_thread2 + 228 2 libsystem_pthread.dylib 0x10b8 _pthread_wqthread + 228 3 libsystem_pthread.dylib 0xe94 start_wqthread + 8 BUG IN LIBDISPATCH: Lingering DISPATCH_WLH_ANON Crashed: com.apple.root.user-initiated-qos.cooperative 0 libdispatch.dylib 0x16ed0 _dispatch_kevent_worker_thread + 2196 1 libsystem_pthread.dylib 0x112c _pthread_wqthread + 344 2 libsystem_pthread.dylib 0xe94 start_wqthread + 8 Crashed: com.apple.root.user-initiated-qos.cooperative 0 libdispatch.dylib 0x2a6d4 _voucher_xref_dispose + 108 1 libdispatch.dylib 0x6ed8 _dispatch_set_priority_and_voucher_slow + 272 2 libdispatch.dylib 0x16638 _dispatch_worker_thread2 + 228 3 libsystem_pthread.dylib 0x10b8 _pthread_wqthread + 228 4 libsystem_pthread.dylib 0xe94 start_wqthread + 8 Obviously reverting to Xcode 14.2 is a short term solution, and bumping the minimum target to iOS 15.2 is out of the question for now, since we still support iOS 14. Hopefully, Apple fixes this soon. Not sure if there's anything we can do until then.
Posted
by
Post not yet marked as solved
0 Replies
1.1k Views
Hi, It is known that if a SwiftUI view contains an @ObservedObject or @StateObject property, the View will inherit @MainActor isolation from the property wrappers. Similarly, the body view-builder is also marked @MainActor. What I'm wondering is why the whole SwiftUI View protocol isn't marked @MainActor. It seems to be a deliberate decision, but AFAICT it would make a lot of sense for all data and operations defined in a view to have main-actor isolation unless marked nonisolated. I'm currently adding @MainActor annotations to an existing codebase, and it's a bit awkward that some views automatically gain this attribute one way or another, while others need it explicitly applied. Is there a rationale that can be shared, or is this something which may be revised in future versions of the framework?
Posted
by
K24
Post marked as solved
2 Replies
885 Views
Hi, Our team is making 'sign with apple' with continuation to use async/await. This is the codes we are using. However, we encountered quite lots of crashes on continuation?.resume(returning: appleIDCredential). final class ASAuthorizationAdapter: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { private var continuation: CheckedContinuation&lt;ASAuthorizationAppleIDCredential, Error&gt;? func signInWithApple() async throws -&gt; ASAuthorizationAppleIDCredential { try await withCheckedThrowingContinuation { continuation in self.continuation = continuation let appleIDProvider = ASAuthorizationAppleIDProvider() let request = appleIDProvider.createRequest() request.requestedScopes = [.fullName, .email] let authorizationController = ASAuthorizationController(authorizationRequests: [request]) authorizationController.delegate = self authorizationController.presentationContextProvider = self authorizationController.performRequests() } } func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { switch authorization.credential { case let appleIDCredential as ASAuthorizationAppleIDCredential: continuation?.resume(returning: appleIDCredential) default: break } } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { continuation?.resume(throwing: error) } func presentationAnchor(for controller: ASAuthorizationController) -&gt; ASPresentationAnchor { (Navigator.default.topMostViewController?.view.window)! } } The crash log says nothing about the cause of the problem. Is There a problem we're missing? Thanks in advance.
Posted
by
Post not yet marked as solved
1 Replies
523 Views
So I have a class like below class DownloadOperation: Operation { private var task : URLSessionDownloadTask! enum OperationState : Int { case ready case executing case finished } // default state is ready (when the operation is created) private var state : OperationState = .ready { willSet { self.willChangeValue(forKey: "isExecuting") self.willChangeValue(forKey: "isFinished") } didSet { self.didChangeValue(forKey: "isExecuting") self.didChangeValue(forKey: "isFinished") } } override var isReady: Bool { return state == .ready } override var isExecuting: Bool { return state == .executing } override var isFinished: Bool { return state == .finished } init( session: URLSession, downloadTaskURL: URL, item: ItemModel, completionHandler: ((URL?, URLResponse?, ItemModel, Error?) -> Void)? ) { super.init() // use weak self to prevent retain cycle task = session.downloadTask( with: downloadTaskURL, completionHandler: { [weak self] (localURL, response, error) in /* if there is a custom completionHandler defined, pass the result gotten in downloadTask's completionHandler to the custom completionHandler */ if let completionHandler = completionHandler { // localURL is the temporary URL the downloaded file is located completionHandler(localURL, response, item, error) } /* set the operation state to finished once the download task is completed or have error */ self?.state = .finished }) } override func start() { /* if the operation or queue got cancelled even before the operation has started, set the operation state to finished and return */ if(self.isCancelled) { state = .finished return } // set the state to executing state = .executing // start the downloading self.task.resume() } override func cancel() { super.cancel() // cancel the downloading self.task.cancel() } } I would like to call it in async func, but I'm having difficulties with converting it to asyn func func getItemsAsync() async { requestStatus = .pending do { let feedsData = try await dataService.fetchAllFeedsAsync() for index in feedsData.indices { var item = feedsData[index] // make sure Item has a URL guard let videoURL = item.url else { return } let operation = DownloadOperation( session: URLSession.shared, downloadTaskURL: videoURL, item: item, completionHandler: { [weak self] (localURL, response, item, error) in guard let tempUrl = localURL else { return } let saveResult = self?.fileManagerService.saveInTemp(tempUrl, fileName: videoURL.lastPathComponent) switch saveResult { case .success(let savedURL): let newItem: ItemModel = .init( id: item.id, player: AVPlayer(url: savedURL) ) await MainActor.run(body: { self?.items.append(newItem) if items.count ?? 0 > 1 { // once first video is downloaded, use all device cores to fetch next videos // all newest iOS devices has 6 cores downloadQueue.setMaxConcurrentOperationCount(.max) } }) case .none: break case .failure(_): EventTracking().track("Video download fail", [ "id": item.id, "ulr": videoURL.absoluteString.decodeURL() ]) } }) let fileCaheURL = downloadQueue.queueDownloadIfFileNotExists2(videoURL, operation) if let fileCaheURL = fileCaheURL { // ... do some other magic } } } catch let error { requestStatus = .error errorMessage = error.localizedDescription } }
Posted
by