If I have the method defined below, does the block ("handler") passed to the method get called on the new thread created by NSOperationQueue? Or does it get called on the thread it was on when passed to methodWithCompletionHandler:?
-(void)methodWithCompletionHandler:(void (^)(NSString *message))handler
{
// Note: We are currently on thread #1. Calling handler(#"my message") here
// will run on thread #1.
NSBlockOperation* someOp = [NSBlockOperation blockOperationWithBlock: ^{
// do some stuff
}];
[someOp setCompletionBlock:^{
// Note: Now someOp is completing, but it's in thread #2. Does calling the handler
// as below also run in thread #2 or thread #1?
handler(#"Some message.");
}];
NSOperationQueue *queue = [NSOperationQueue new];
[queue addOperation:someOp];
}
From the documentation:
The exact execution context for your completion block is not
guaranteed but is typically a secondary thread.
http://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004591-RH2-SW36
In the example you have posted, the block in someOp would be executed on a different thread.
In general, blocks act just like a regular function. They run on the thread that called them (unless the block itself does something to call another thread etc...)
Related
I have this code which I have some tasks I want to do it parallel, the problem is a movie object is release on each run loop before dispatch can process it. Is there a way to retain this in ARC ? Now I process most of logic out side the dispatch and pass it in with __block, but if it is a time consuming process and want to process it in the dispatch block what should I do ?
for (HTMLNode *movie in movieContainer) {
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// time consuming process on movie object
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// combine the results
});
Most of the time, you don't have to. Blocks automatically capture all variables that are used by default, however, when using fast iteration, there is an exception.
Because fast iteration uses __unsafe_unretained raw pointers instead of strong ones (for speed), you can simply qualify your iteration variable with strong in this scenario:
for (HTMLNode __strong *movie in movieContainer) {
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// time consuming process on movie object
});
create a local variable with the keyword __strong and affect it the movie object. Then use this strong local variable in your dispatch_async call.
manual retain release
#import <objc/runtime.h>
id objc_retain(id);
void objc_release(id);
objc_retain(object);
objc_release(object);
or
variable with
__strong
So here is what I've got:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), ^{
bool ready = some_function();
if( ready ) {
do_smth_here()
} else {
//invoke this block one more time after 0.1 sec
}
});
The problem is how can I get the reference to the current block?
Instead of jumping through the hoops shown above, I typically declare an instance method that I can call that, internally, takes care of the retriggers as necessary. That way, any given block is one-shot, but the re-trigger creates a new block.
As long as the block creation isn't terribly expensive -- which it won't be if the state is coming from whatever encapsulates the instance method -- it is efficient enough and a heck of a lot simpler.
- (void) retriggerMethod
{
... do stuff here, assuming you want to do it on first invocation ...
dispatch_after( ..., ^{
[self retriggerMethod];
});
}
You can restructure it as needed. And you can easily add a BOOL instance variable if you want to protect against simultaneous retriggers, etc...
This also provides a convenient hook for canceling; just add a BOOL to the instance that indicates whether the next invocation should really do anything and re-schedule.
Jeffrey Thomas's answer is close, but under ARC, it leaks the block, and without ARC, it crashes.
Without ARC, a __block variable doesn't retain what it references. Blocks are created on the stack. So the callback variable points to a block on the stack. When you pass callback to dispatch_after the first time (outside of the block), dispatch_after successfully makes a copy of the block on the heap. But when that copy is invoked, and passes callback to dispatch_after again, callback is a dangling pointer (to the now-destroyed block on the stack), and dispatch_after will (usually) crash.
With ARC, a __block variable of block type (like callback) automatically copies the block to the heap. So you don't get the crash. But with ARC, a __block variable retains the object (or block) it references. This results in a retain cycle: the block references itself. Xcode will show you a warning on the recursive dispatch_after call: “Capturing 'callback' strongly in this block is likely to lead to a retain cycle”.
To fix these problems, you can copy the block explicitly (to move it from the stack to the heap under MRC) and set callback to nil (under ARC) or release it (under MRC) to prevent leaking it:
__block void (^callback)() = [^{
if(stop_) {
NSLog(#"all done");
#if __has_feature(objc_arc)
callback = nil; // break retain cycle
#else
[callback release];
#endif
} else {
NSLog(#"still going");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
} copy];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Obviously you can drop the #if and just use the branch appropriate for your memory management.
I think this is the code your looking for:
__block void (^callback)();
callback = ^{
bool ready = some_function();
if( ready ) {
do_smth_here()
} else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Thanks to ^ Blocks Tips & Tricks
I am hooked into SpringBoard method, i want to wait a certain event to happen and then continue my code, but whatever i try - i think it pauses the main thread and all threads stop then. My code is:
+(void) startc {
while([currentNumber isEqual:#""])
{
NSLog(#"waiting until currentNumber is not empty %#", currentNumber);
}
}
id replaced_SBCallAlert_initWithCall_(id self, SEL _cmd, CTCallRef call) { // Note the
NSLog(#"calling replaced");
[cdBackground startc];
original_SBCallAlert_initWithCall_(sbc, scc, cls);
return NULL;
}
currentNumber is updated in another thread, but this code blocks it.
Your while loop in startc is effectively a spin lock, and will prevent any further progress on a thread executing it until currentNumber is not #"". If that same thread is the one responsible for changing currentNumber, then yes - you have a deadlock. It looks like this is the case, as I guess you're expecting the call original_SBCallAlert_initWithCall_ to change this variable but are getting stuck inside the previous line's startc call.
In this case, you'll have to change the way your program is designed. You could put startc in a background thread (look at NSThread) and use either another spin lock, NSCondition or key-value observing to "wake up" when currentNumber has changed. You can then use NSObject performSelectorOnMainThread … (assuming you have a runloop) to kick off your code again in the "main" thread, or carry on in your background thread.
When I call performSelectorInBackground several times, would the job be queued on same thread?
so first one be performed first and so on?
Or, would it run in separate thread?
Thank you
A new thread is created with each call to -performSelectorInBackground:withObject:
From http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW13
Using NSObject to Spawn a Thread
In iOS and Mac OS X v10.5 and later, all objects have the ability to spawn a new thread and use it to execute one of their methods. The performSelectorInBackground:withObject: method creates a new detached thread and uses the specified method as the entry point for the new thread. For example, if you have some object (represented by the variable myObj) and that object has a method called doSomething that you want to run in a background thread, you could could use the following code to do that:
[myObj performSelectorInBackground:#selector(doSomething) withObject:nil];
The effect of calling this method is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters. The new thread is spawned immediately using the default configuration and begins running. Inside the selector, you must configure the thread just as you would any thread. For example, you would need to set up an autorelease pool (if you were not using garbage collection) and configure the thread’s run loop if you planned to use it. For information on how to configure new threads, see “Configuring Thread Attributes.”
They will be executed in the same time, NOT one after the other,
try this to have an idea:
-(void)prova1{
for (int i = 1; i<=10000; i++) {
NSLog(#"prova UNO:%i", i);
}
}
-(void)prova2{
for (int i = 1; i<=10000; i++) {
NSLog(#"_________prova DUE:%i", i);
}
}
SEL mioMetodo = NSSelectorFromString(#"prova1");
[self performSelectorInBackground:mioMetodo withObject:nil];
SEL mioMetodo2 = NSSelectorFromString(#"prova2");
[self performSelectorInBackground:mioMetodo2 withObject:nil];
you'll get:
...
___prova DUE:795
prova UNO:798
___prova DUE:796
prova UNO:799
___prova DUE:797
prova UNO:800
___prova DUE:798
prova UNO:801
___prova DUE:799
prova UNO:802
___prova DUE:800
prova UNO:803
___prova DUE:801
...
if you want a queue with 1 method after the other, try to add the 2 methods to a NSOperationQueue and set its setMaxConcurrentOperationCount to 1...
I would like to pass in different blocks into a method. The method would subsequently use the passed in block as parameter to dispatch_async.
I have my block declared like this:
typedef int (^ComputationBlock)(int);
The class method that accepts the block is implemented as:
- (void)doSomething:(int)limit withBlock:(ComputationBlock)block;
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// typical in-lined block for dispatch_async:
dispatch_async(queue, ^{
// do some work here
});
// I want to pass in the block as the 2nd parameter to dispatch_async
// but the compiler will warn me of a type mismatch unless I cast
// the block like:
dispatch_async(queue, (dispatch_block_t)block);
}
#end
Is it okay to typecast the 'block' parameter as dispatch_block_t?
No, that's not cool to do -- the block passed to dispatch_async needs to take no parameters and return nothing. Casting your ComputationBlock to that would be a Bad Idea (it's not nice to fool mother nature).
Simply wrap your block that you want to call inside one of the right type:
dispatch_async(queue, ^{ block(0); } );
(note that you also need to supply a parameter to your ComputationBlock when you invoke it.)
It may compile, but it won't work. dispatch_block_t blocks must not take any arguments and must not have a return value.
Pass value using __block
__block int backValue;
it can modify in block