Any ideas to cancel a function in the middle? Swift iOS - ios

I call a network task to fetch some JSON when user selects a cell in a UICollectionView. This is asynchronous so the UI remains active whilst the data is being retrieved. Allowing user to select another cell in the UICollectionView. I do not want to stop this but I do want a way to cancel the first function call and call the new method for the now selected cell.
Is there a way to in perhaps didDeselectItemAt indexPath: to cancel any currently executing tasks?
I was thinking to place a "please wait" modal view over the UI which would prevent a second cell selection until the function returned. Is this my best option or is there a better way?

You can use a NSOperationQueue to create and keep track of the asyncronous requests and cancel them when necessary.
See the answers to this other question here:
GCD cancel async block?

By maintaining separate threads using NSOperationQueue enables controls over tasks in the middle of execution whereas GCD wont allow the same but both works for background and foreground execution of particular task mechanism.
GCD is a lightweight way to represent units of work that are going to be executed concurrently. You don’t schedule these units of work; the system takes care of scheduling for you.
NSOperation adds a little extra overhead compared to GCD, but you can add dependency among various operations and re-use, cancel or suspend them.
Sample:
var backgroundQueue = NSOperationQueue()
backgroundQueue.addOperationWithBlock(){
println("hello from background")
NSOperationQueue.mainQueue().addOperationWithBlock(){
self.theLabel.text = "updated from main thread"
}
}
Now can do various operation provided NSOperationQueue over backgroundQueue variable.

You can submit your networking tasks as NSOperations to an NSOperationQueue.
NSOperation has a cancel method, and NSOperationQueue has a cancelAllOperations method.

Related

Threading with iOS and waiting for function completion

I'm calling a function on a thread in my project.
[self performSelectorInBackground:#selector(shortVibration) withObject: nil];
It's called in a loop.
I would like for the function to be called on its own thread.
I don't want it to be called at the same time (if this thread Call is in a loop... and it is)
So, I don't want to call my thread function again until the last one is done executing.
How can I do this?
don't want it to be called at the same time
That suggests a "serial queue". That could be a dispatch queue or an operation queue. But a serial queue is one that can run only one task at a time.
Or, you can decouple the loop from the repeating vibration and set up a timer to run while your loop progresses which will repeatedly call your vibration routine and then cancel the timer at the end of the loop. You can either use a standard NSTimer and have it dispatch the calls to whatever queue you want, or you can use a GCD timer, which you can schedule on a background queue.
It depends upon the details of how this vibration routine works and the nature of your loop. We'd need more detail (e.g. describe the broader problem and the nature of this "vibrate" routine) to help you further.
Perhaps you should take a look at NSOperationQueue which allows you to call functions in own created Queues. The Queues are executed on an own Thread.
For example:
NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc]init];
backgroundQueue.maxConcurrentOperationCount = 1;
backgroundQueue.name = #"com.foo.bar";
[_backgroundQueue addOperationWithBlock:^{
do what you want.... here you also have access to properties in your class.
}];
With the operationCount you can handle the count of parallel executed operations. You can also create an own Subclass of NSOperation and execute your code there. Then you have to add the Operation like this [_backgroundQueue addOperation:SubclassOfNSOperation].
I hope this helps you a little. Out of your Question I can't get more information to help you more in detail. Post some code perhaps.

Swift handle lots of complex operations

I'm working on a Swift project with complicated notification calculations. I'm looping through an array of objects which I need to do a very complex operation to determine when to schedule notifications. Currently I am doing:
for item in items {
//some logic here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
//complex operation here, then schedule notification
}
}
Unfortunately this is proving to be slow since I am doing this for a bunch of objects that are all trying to use the same queue. Sometimes it doesn't finish scheduling the notifications before the user leaves the app. What are my options to improve the performance? I was thinking instead of having everything use the global high priority queue I could create new queues each time somehow so they are not waiting on each other?
First, I don't think you need to use the "main thread" for calculation, the main thread is mainly for UI updates. You should use background thread to handle those heavy operations and schedule notifications. Otherwise you app is going to be very laggy and not responsive(as you main thread is occupied by those operations)
Second, in stead of firing multiple main thread operations using a for loop. You should put the code in this way.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
for item in items {
//some logic here
//complex operation here, then schedule notification
}
}
As you didnt provide code of the complex operation, can't give any advise on that part. Feel free to add follow up questions. :D

Asynchronous swift 3

I need to make an asynchronous call so that the second method is only called after the first one is completed.Both methods are network calls. Something like this:
signIn()
getContacts()
I want to make sure that getContacts only gets called after the signIn is completed. FWIW, I can't edit the methods signatures because they are from a Google SDK.
This is what I tried:
let queue = DispatchQueue(label: "com.app.queue")
queue.async {
signIn()
getContacts()
}
Async calls, by their nature, do not run to completion then call the next thing. They return immediately, before the task they were asked to complete has even been scheduled.
You need some method to make the second task wait for the first to complete.
NauralInOva gave one good solution: use a pair of NSOprations and make them depend on each other. You could also put the 2 operations into a serial queue and the second one wouldn't begin until the first is complete.
However, if those calls trigger an async operation on another thread, they may still return and the operation queue may trigger the second operation (the getContacts() call without waiting for signIn() to complete.
Another option is to set up the first function to take a callback:
signIn( callback: {
getContacts()
}
A third option is to design a login object that takes a delegate, and the login object would call a signInComplete method on the delegate once the signIn is complete.
This is such a common thing to do that most networking APIs are built for it "out out of the box." I'd be shocked if the Google API did not have some facility for handling this.
What Google framework are you using? Can you point to the documentation for it?
You're looking for NSOperation. You can use NSOperation to chain operations together using dependencies. Once one operation complete's it can pass it's completion block to the next operation. An example for your use case might be:
// AuthOperation is a subclass of NSOperation
let signInOperation = AuthOperation()
// ContactsOperation is a subclass of NSOperation
let getContactsOperation = ContactsOperation()
getContactsOperation.addDependency(signInOperation)
Ray Wenderlich has a great tutorial covering NSOperation. The tutorial uses a downloading operation to load images asynchronously with a dependency that will filter the photo upon completion of the network request.
There is also a great sample project by Apple that uses operations with asynchronous network requests.

Whether those two ways of dispatching work to main thread (CGD and NSOperationQueue) are equivalent?

I'm curious whether those two types to dispatch work to main queue are equivalent or maybe there are some differentials?
dispatch_async(dispatch_get_main_queue()) {
// Do stuff...
}
and
NSOperationQueue.mainQueue().addOperationWithBlock { [weak self] () -> Void in
// Do stuff..
}
There are differences, but they are somewhat subtle.
Operations enqueued to -[NSOperationQueue mainQueue] get executed one operation per pass of the run loop. This means, among other things, that there will be a "draw" pass between operations.
With dispatch_async(dispatch_get_main_queue(),...) and -[performSelectorOnMainThread:...] all enqueued blocks/selectors are called one after the other without spinning the run loop (i.e. allowing views to draw or anything like that). The runloop will continue after executing all enqueued blocks.
So, with respect to drawing, dispatch_async(dispatch_get_main_queue(),...) and -[performSelectorOnMainThread:...] batch operations into one draw pass, whereas -[NSOperationQueue mainQueue] will draw after each operation.
For a full, in-depth investigation of this, see my answer over here.
At a very basic level they are not both the same thing.
Yes, the operation queue method will be scheduled on GCD queue. But it also gets all the rich benefits of using operation queues, such as an easy way to add dependent operations; state observation; the ability to cancel an operation…
So no, they are not equivalent.
Yes there are difference in GCD and NSOperation.
GCD is light weight can be used to give flavor of multithreading like loading profile pic, loading web page, network call that surely returns at earliest.
NSOperation queue 1. Usually used to make heavy network calls, sort thousand's of record etc.2. Can add new operation, delete, get current status at any operation3. Add completion handler4. get operation count etc are added advantages over GCD

NSNotification - observer with multiple events to trigger

As it stands, NSNotifications allow for a target-action mechanism in response to one post / event.
I would like to have a notification which triggers an action (runs a function) only after two events have been triggered.
The scenario is that I have two asynchronous processes which need to complete before I can call the function. Perhaps I'm missing something, but I haven't found a way to do this. Or maybe I'm not thinking of an obvious reason why this would be a really bad idea?
Also, some of my terminology may be off, so please feel free to edit and fix it.
There are many possibilities on how you can implement this. They all center around keeping track of which processes are finished. The best way depends on how your background processes are implemented.
If you are using NSOperationQueue you could add a third operation that has the other two operations as a dependency. That way you won't have to take care of notifications at all.
Otherwise you can can count how many operations have finished and execute your code when the counter reaches the right value. GCD has dispatch groups as a nice abstraction for this.
First you create a dispatch group:
let group = dispatch_group_create()
Then you enter the group for each background process:
dispatch_group_enter(group)
Finally you can register an block that gets called when the group becomes empty, that is when each dispatch_group_enter is balanced by an dispatch_group_leave:
dispatch_group_notify(group, dispatch_get_main_queue()) {
// All processes are done.
}
After each of your processes finish you leave the group again:
dispatch_group_leave(group)
It's important to call dispatch_group_enter before calling dispatch_group_notify or your block will be scheduled immediately as the group is already empty.
After your notify block was executed you can reuse the queue or discard it.

Resources