I have a list of files i need to upload to my server.
I want to upload each file only if the file before it uploaded successfully.
I'm looking for an elegant way to implement this.
For example using coroutines like feature.
So is there a feature like coroutines in swift?
Is there any other elegant way to implement this?
Thanks
You could use an OperationQueue. Create one like this:
lazy var queue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
and then add an operation to it like this:
self.queue.addOperation {
// The code you want run in the background
}
Having set the maxConcurrentOperationCount to 1 it operates as a serial queue not running the next task until the current one has finished.
That's the most basic functionality but there are all kinds of more advanced things you can do so check out the documentation OperationQueue
Why not create a List of files and on the completion handler of one upload just check if the list is not empty and kick off the next one? Rather than a complicated coroutines setup I think it can be simpler by just maintaining an upload list/queue.
You can create a serial queue for that, using Grand Central Dispatch. Compared to OperationQueue suggested in on of the answers given here it has the advantage of saving quite an amount of overhead. Please see this post for details on that.
This creates the serial queue:
let serialQueue = DispatchQueue(label: "someQueueIdentifier", qos: .background)
Choose the quality of service parameter according to your needs.
Then, you could have a loop, for example, from which you place your background jobs into this queue:
while <condition> {
serialQueue.async {
// do background job
}
}
A serial queue will run one job at a time and the whole queue will be executed asynchronously in the background.
Related
I have a singleton that manages an array. This singleton can be accessed from multiple threads, so it has its own internal DispatchQueue to manage read/write access across threads. For simplicity we'll say it's a serial queue.
There comes a time where the singleton will be reading from the array and updating the UI. How do I handle this?
Which thread my internal dispatch queue is not known, right? It's just an implementation detail I'm to not worry about? In most cases this seems fine, but in this one specific function I need to be sure it uses the main thread.
Is it okay to do something along the lines of:
myDispatchQueue.sync { // Synchronize with internal queue to ensure no writes/reads happen at the same time
DispatchQueue.main.async { // Ensure that it's executed on the main thread
for item in internalArray {
// Pretend internalArray is an array of strings
someLabel.text = item
}
}
}
So my questions are:
Is that okay? It seems weird/wrong to be nesting dispatch queues. Is there a better way? Maybe something like myDispatchQueue.sync(forceMainThread: true) { ... }?
If I DID NOT use DispatchQueue.main.async { ... }, and I called the function from the main thread, could I be sure that my internal dispatch queue will execute it on the same (main) thread as what called it? Or is that also an "implementation detail" where it could be, but it could also be called on a background thread?
Basically I'm confused that threads seem like an implementation detail you're not supposed to worry about with queues, but what happens on the odd chance when you DO need to worry?
Simple example code:
class LabelUpdater {
static let shared = LabelUpdater()
var strings: [String] = []
private let dispatchQueue: dispatchQueue
private init {
dispatchQueue = DispatchQueue(label: "com.sample.me.LabelUpdaterQueue")
super.init()
}
func add(string: String) {
dispatchQueue.sync {
strings.append(string)
}
}
// Assume for sake of example that `labels` is always same array length as `strings`
func updateLabels(_ labels: [UILabel]) {
// Execute in the queue so that no read/write can occur at the same time.
dispatchQueue.sync {
// How do I know this will be on the main thread? Can I ensure it?
for (index, label) in labels.enumerated() {
label.text = strings[index]
}
}
}
}
Yes, you can nest a dispatch to one queue inside a dispatch to another queue. We frequently do so.
But be very careful. Just wrapping an asynchronous dispatch to the main queue with a dispatch from your synchronizing queue is insufficient. Your first example is not thread safe. That array that you are accessing from the main thread might be mutating from your synchronization queue:
This is a race condition because you potentially have multiple threads (your synchronization queue’s thread and the main thread) interacting with the same collection. Rather than having your dispatched block to the main queue just interact objects directly, you should make a copy of of it, and that’s what you reference inside the dispatch to the main queue.
For example, you might want to do the following:
func process(completion: #escaping (String) -> Void) {
syncQueue.sync {
let result = ... // note, this runs on thread associated with `syncQueue` ...
DispatchQueue.main.async {
completion(result) // ... but this runs on the main thread
}
}
}
That ensures that the main queue is not interacting with any internal properties of this class, but rather just the result that was created in this closure passed to syncQueue.
Note, all of this is unrelated to it being a singleton. But since you brought up the topic, I’d advise against singletons for model data. It’s fine for sinks, stateless controllers, and the like, but not generally advised for model data.
I’d definitely discourage the practice of initiating UI controls updates directly from the singleton. I’d be inclined to provide these methods completion handler closures, and let the caller take care of the resulting UI updates. Sure, if you want to dispatch the closure to the main queue (as a convenience, common in many third party API), that’s fine. But the singleton shouldn’t be reaching in and update UI controls itself.
I’m assuming you did all of this just for illustrative purposes, but I added this word of caution to future readers who might not appreciate these concerns.
Try using OperationQueues(Operations) as they do have states:
isReady: It’s prepared to start
isExecuting: The task is currently running
isFinished: Once the process is completed
isCancelled: The task canceled
Operation Queues benefits:
Determining Execution Order
observe their states
Canceling Operations
Operations can be paused, resumed, and cancelled. Once you dispatch a
task using Grand Central Dispatch, you no longer have control or
insight into the execution of that task. The NSOperation API is more
flexible in that respect, giving the developer control over the
operation’s life cycle
https://developer.apple.com/documentation/foundation/operationqueue
https://medium.com/#aliakhtar_16369/concurrency-in-swift-operations-and-operation-queue-part-3-a108fbe27d61
In my application, I've got a background thread which make sure the local database (core data) is synchronized with server. There are multiple ways to trigger the processing (notificationServer observer, timer, ...). However, I want to make sure there is only one instance processing the data at the time. So, if a processing task is triggered while "old" synchronization task is running, I want it to wait for the previous task to finish.
My current code looks something like this:
backgroundContext = persistance.persistentContainer.newBackgroundContext()
// this is an instance variable which will be shared by all the threads
...
...
#objc func managedObjectContextDidSave(notification: NSNotification) {
backgroundContext.perform {
self.processAllHisotory()
}
}
Is it guaranteed that if I perform multiple tasks on the same context, they will not get executed in parallel? If not, what is the best way to synchronize such tasks?
If you make a DispatchQueue, it is a serial queue. A new task cannot start while a task is in progress. In effect, the serial queue is a lock.
I just read long introduction to NSOperationQueues and NSOperation here.
My question is the following. I need to run two operations is the same time. When both those tasks finished I need to make another calculations based on results from two finished operations. If one of the operations fails then whole operation should also fails. Those two operations does not have dependencies and are completely independent from each other so we can run them in parallel.
How to wait for this 2 operation to finish and then continue with calculations? I don't want to block UI Thread. Should I make another NSOperation that main method is creating two NSOperations add them to some local (for this operation) queue and wait with waitUntilAllOperationsAreFinished method. Then continue calculations?
I don't like in this approach that I need to create local queue every time I creating new operation. Can I design it that way that I can reuse one queue but wait only for two local operations? I can imagine that method waitUntilAllOperationsAreFinished can wait until all tasks are done so it will blocks when a lot of tasks will be performed in parallel. Any design advice? Is creating NSOperationQueue expensive? Is there any better ways to do it in iOS without using NSOperation & NSOperationQueue? I'm targeting iOS 9+ devices.
In Swift 4, you can do it this way:
let group = DispatchGroup()
// async
DispatchQueue.global().async {
// enter the group
group.enter()
taskA(onCompletion: { (_) in
// leave the group
group.leave()
})
group.enter()
taskB(onCompletion: { (_) in
group.leave()
})
}
group.notify(queue: DispatchQueue.main) {
// do something on task A & B completion
}
And there is an excellent tutorial on GCD from raywenderlich.com.
I have 5 timers running with a different time interval.All these timers calling the same function.
At a certain time, one or more timer function trying to access the same method, this will crash my app.
How I can implement NSOperation queue for this particular scenario.
Appreciate your help.
You can create a dispatch queue with label.
let queue = DispatchQueue(label: "update") // later on your "other threads"
queue.sync {
//perform any task you want
}
In your each timer use the above code. In this way all will be able to execute this "update" thread only when it will be free
I want to know As we all know how asynchronous task are necessary for concurrency but Wanted to know why we need the synchronous tasks. while we can achieve the same with the normal usage of function.
Thanks & regards
Rohit
When you calls something synchronously, it means that 'the thread that initiated that operation will wait for the task to finish before
continuing'. Asynchronous means that it will not wait for finish the task.
synchronous calls stops your current action and returns when the call returned. with asynchronous calls you can continue.
synchronous is the opposite of asynchronous code, and therefore is ordinary code.
At the end, if asynchronous is totally out of scope then you will not emphasize the word synchronous.
It helps to synchronise threads, as the name suggests.
consider a typical usage of GCD async and sync (pseudo)
async background_thread {
//1 call webservice or other long task that would block the main thread
sync main_thread {
//2 update UI with results from 1
}
//3 do something else that relies on 2
}
now if 2 was in an async and you needed to do something at 3 that relies on the updates at 2 to have happened, then you are not guaranteed (and most likely wont) get the behaviour you are expecting. instead, you use a sync to make sure that the task is completed before continuing the execution in the background thread.
If you are asking now, why not just take out the sync/async around 2 so it executes in order anyway? the problem is, the UI must not be updated on a background thread otherwise the behaviour is undefined (which usually means the UI lags a lot). So in essence what happens is the background thread waits at 2's sync until the main thread gets round to executing that block, then it will continue with the rest of the execution on the background thread.
If you were dealing with a task that doesnt require the main thread (or some other thread) to execute properly, then yes you may as well take out the sync at 2.
This is just one example of how a sync is useful, there are others if you are doing advanced threading in your app.
Hope this helps
Typically it's because you want to do an operation on a specific different thread but you need the result of that operation. You cannot do the operation asynchronously because your code will proceed before the operation on the other thread completes.
Apple has a very nice example:
func asset() -> AVAsset? {
var theAsset : AVAsset!
self.assetQueue.sync {
theAsset = self.getAssetInternal().copy() as! AVAsset
}
return theAsset
}
Any thread might call the asset method; but to avoid problems with shared data, we require that only functions that are executed from a particular queue (self.assetQueue) may touch an AVAsset, so when we call getAssetInternal we do it on self.assetQueue. But we also need the result returned by our call to getAssetInternal; hence the call to sync rather than async.