How can I define when a NSOperationQueue will send the next job - nsoperation

I would like to add multiple NSOperations to a NSOperationQueue , but be in control of when the next operation will be sent.
How can I configure the NSOperationQueue to "delegate" a "send next job" method to the owner of the NSOperationQueue

You can do this: You can setup two NSOperations and make one dependent on the other and add it to the same queue. The first is a dummy operation and triggering that will trigger the second operation. So you can add all the instances of the second operation to the queue and whenever you want to trigger it, just add the first operation to the same queue and it will trigger the second operation immediately (since the first one is dummy and blank).

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.

Any ideas to cancel a function in the middle? Swift 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.

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.

How to update UI before nsoperation will start and or end

2 part question but related so will keep in the same thread:
I'm adding NSOperations to a NSOperationQueue. I need to know when the operation will start and when it ends in order to update the UI.
I thought about adding a "start handler" block to run in the nsoperation as well as a "completion handler" in the NSOperation
Something like
-(id)initOperationWithStartBlock:(StartBlock)startblock completionBlock:(CompletionBlock)completionBlock
but believe that there is a better way to get this from the queue itself.
How can this be done?
I would also like to know the index of the job sent by the NSOperationQueue.
I've tried doing
[[self.myQueue operations] indexForObject:operation]
but the index is always the zeroth index - because the completed jobs were removed from the nsoperationqueue array before I could check the jobs index.
Any way to preserve them?
You need to use Key-Value-Observing pattern in IOS. So for this you need to setup observers in your controller to look for changes to isFinished and isExecuting to catch start and finish hooks.
It depends if you want to perform something from within your object upon starting or elsewhere in your code. From what you are saying (you want to update the UI), this sounds like you want to act outside of your object, but I don't know your program. You have two options:
1) If you want to act in your object upon starting the operation from within the same object, use key-value observation and observe isExecuting with self as the observer and the observed. Don't forget that you will get called whether it goes from NO to YES (starting) or YES to NO (done).
2) If you want to perform an action outside of the object, I would rather recommend to use the very general NSNotification with NSNotificationCenter and within your main, post a notification such as #"willStart" and #"didComplete". In any other object, register as an observer for your notifications.
Either way, don't forget that notifications are sent in the current threads but the UI must be updated on the main thread. You don't know on what thread observe:keyPath: is called. You may need to call performSelectorOnMainThread to update the UI or you can even use the convenient and useful nsoperationqueue mainqueue with a addOperationWithBlock with your UI code. If you use the NotificationCenter, then you can simply yourself post on the main thread with nsobject performSelectorOnMainThread

Is [NSOperationQueue mainQueue] guaranteed to be serial?

That is, if we queue the same thing several time there will be no concurrency.
The one we queued first will be executed first.
I mean there is only one main thread right?
I have found a nice answer here:
NSOperationQueue and concurrent vs non-concurrent
So make all added operations serial you can always set:
[[NSOperationQueue mainQueue] setMaxConcurrentOperationCount:1];
And the answer is... YES and NO
when you create a new NSOperation to add to your queue, you can use
- (void)setQueuePriority:(NSOperationQueuePriority)priority
according to the documentation, the queue will use this priority, and other factors as inter dependency to decide what operation will be executed next.
As long as your operations have the same priority and no inter-operation dependencies, they should be executed in the same order you added them, maybe with other, system related operations, inserted between them.
From documentation:
The NSOperationQueue class regulates the execution of a set of NSOperation objects. After being added to a queue, an operation remains in that queue until it is explicitly canceled or finishes executing its task. Operations within the queue (but not yet executing) are themselves organized according to priority levels and inter-operation object dependencies and are executed accordingly. An application may create multiple operation queues and submit operations to any of them.
Inter-operation dependencies provide an absolute execution order for operations, even if those operations are located in different operation queues. An operation object is not considered ready to execute until all of its dependent operations have finished executing. For operations that are ready to execute, the operation queue always executes the one with the highest priority relative to the other ready operations. For details on how to set priority levels and dependencies, see NSOperation Class Reference.
About threads:
Although you typically execute operations by adding them to an operation queue, doing so is not required. It is also possible to execute an operation object manually by calling its start method, but doing so does not guarantee that the operation runs concurrently with the rest of your code. The isConcurrent method of the NSOperation class tells you whether an operation runs synchronously or asynchronously with respect to the thread in which its start method was called. By default, this method returns NO, which means the operation runs synchronously in the calling thread.
When you submit a nonconcurrent operation to an operation queue, the queue itself creates a thread on which to run your operation. Thus, adding a nonconcurrent operation to an operation queue still results in the asynchronous execution of your operation object code.
So, if I understand correctly here will be no concurrency.

Resources