PerformSelector with Delay 0? [duplicate] - ios

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does -performSelector:withObject:afterDelay: work?
I often use this code to let the UI finish its business before calling a long-running method:
[obj performSelector:#selector(go) withObject:nil afterDelay:0];
But what does it do?
My personal interpretation has always been that the go method is called on the next run loop, but surely that's not even right.

Calling it with delay 0 will indeed invoke this method on the next pass through the runloop.
IIRC, what it does is set up a struct that represents the target and action, and attach a CFRunLoopSource to the runloop that, when triggered, will invoke the action on the target. It then signals the runloop to tell it that it has a ready source. This means that the next time the runloop processes its sources (i.e. the next pass through the runloop), it will perform your delayed selector.

Related

What code is put on the Event Loop - the Future body or the call to execute upon its completion (then)?

I have a few basic questions about Dart Futures that I can't seem to get an answer to myself. Considering the following code:
Future(
() => print('from Future') // 1
).then(
(_) => print('after Future') // 2
);
What is put on the Event Loop, code block 1 or 2?
If 1 is put on the Event Loop, is 2 executed immediately after it, synchronously, or is it put on the Event Loop as well, for later execution?
If 2 is executed immediately, would it ever make sense for 2 to be:
Future.delayed(someDuration, () => print('after Future'));
What would the use case be? Like to split a longer 'task' so that other code is run in between? Is it something that is actually done in practice, like in Flutter, to prevent 'jank'?
Edit: I found a very insightful article: https://webdev-angular3-dartlang-org.firebaseapp.com/articles/performance/event-loop#how-to-schedule-a-task, which kind of answers pretty much every single question I asked here.
The constructor you are calling is Future() which are documented as:
Creates a future containing the result of calling computation asynchronously with Timer.run.
If the result of executing computation throws, the returned future is completed with the error.
If the returned value is itself a Future, completion of the created future will wait until the returned future completes, and will then complete with the same result.
If a non-future value is returned, the returned future is completed with that value.
https://api.dart.dev/stable/2.8.2/dart-async/Future/Future.html
Where Timer.run is documented as:
Runs the given callback asynchronously as soon as possible.
This function is equivalent to new Timer(Duration.zero, callback).
https://api.dart.dev/stable/2.8.2/dart-async/Timer/run.html
So, since we are creating a timer which are already completed, it will immediately be put on the event loop.
So with this knowledge we can answer your questions:
What is put on the Event Loop, code block 1 or 2?
Block 1 is put on the event loop. Since block 2 is dependent on the result from block 1, it will not be put on any queue. Instead, block 2 will be notified when block 1 has returned its result.
If 1 is put on the Event Loop, is 2 executed immediately after it, synchronously, or is it put on the Event Loop as well, for later execution?
As far as I understand the documentation, block 2 will be executed immediately synchronously as part of the block 1 is completed (unless the future as has already been completed which then will trigger a microtask):
Register callbacks to be called when this future completes.
When this future completes with a value, the onValue callback will be called with that value. If this future is already completed, the callback will not be called immediately, but will be scheduled in a later microtask.
https://api.dart.dev/stable/2.8.2/dart-async/Future/then.html
If 2 is executed immediately, would it ever make sense for 2 to be:
The specific example does not make much sense. But yes, you can use the Future.delayed if you want to schedule smaller tasks on the event loop. It should be noted that Dart are single threaded so you cannot schedule tasks to be running in another thread by using Future.delayed.
But in the context of Flutter, you properly want to have multiple smaller tasks so the UI can be drawn between each task. But if you are going to make some heavy calculations, you should properly use an Isolate to run these in another thread.

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.

iOS blocks are called on what thread?

I'm learning about blocks from a Stanford video. I'm now at the part which explains core data. The teachers mentions something about:
- (void)openWithCompletionHandler:(void (^)(BOOL success))completionHandler;
He said that completionhandler block will be called in the thread which called the method. So basically the method runs async but the blocks get called on the thread, lets assume main.
So my question is do all blocks run on the thread from where the method call was made. To illustrate why I ask this question, I have a Async class which does request to a server.
The format of all these methods is like this:
- (void) getSomething:(id <delegateWhatever> const)delegate{
goto background thread using GCD..
Got result from server...
Go back to main thread and call the delegate method...
}
When I use blocks I do not need to worry about going back to main thread if they will be called where the call was made?
Hope this is clear,
Thanks in advance
If something runs asynchronously, you should read a documentation to know on which thread, e.g. the completion block will be executed. If it is your code, you are in charge here, you can use global GCD queues, you can create your own queue and execute it there or whatever...
In general, blocks behaves like a function or a method call, it is executed on thread, which calls it. It is even possible that the same block will be executed from 2 different threads at the same time.
And just to be clear: Even if you are using blocks, you need to care about going back to main thread, of course if it is necessary
Nothing forces blocks to be called on a particular thread, so it depends on the specific method whether or not you need to worry about its callback being on the main thread. (In practice I don't remember ever seeing a library where a method called on the main thread would not call its completion handler also on the main thread. But you still need to read the documentation of the specific library and method you are using, as always.)

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

Context switches on iOS using "performSelectorOnMainThread"

I have weird threading issues on iOS. Consider a simple method like this:
- (BOOL)doSomething
{
[self doA];
[self doB];
}
This method should only run in context of the main thread. I need to call this method from a worker thread. I use performSelectorOnMainThread for this purpose.
If I do everything as explained here. Can a context switch happen between doA and `doB?
(I don't think so, I just want to make sure that my understanding is right here)
By "context switch" I assume you mean the main thread switching to some other main thread event (as you could always switch to another worker thread at any time).
However, main thread will finish all of doSomething before doing anything else.
Excerpt from performSelectorOnMainThread:
This method queues the message on the run loop of the main thread
using the common run loop modes—that is, the modes associated with the
NSRunLoopCommonModes constant. As part of its normal run loop
processing, the main thread dequeues the message (assuming it is
running in one of the common run loop modes) and invokes the desired
method. Multiple calls to this method from the same thread cause the
corresponding selectors to be queued and performed in the same same
order in which the calls were made.

Resources