Method with blocks inside NSOperation - how does it work? - objective-c

I'm working on an iOS project that has to work from iOS4. I have an NSOperationQueue and I add an operation. The main method of the operation looks something like this:
-(void)main
{
[self.client getStuffSuccess:^(Stuff *s) {
//Do something on success
} failure:^(NSError *error) {
//Do something on failure
}
}
The code inside the block will only be called when getStuff calls success or failure. I thought that in the meanwhile, my operation would be removed from the NSOperationQueue and the block wouldn't be called. However, I tested it and the block was in fact called. It's called no matter if the client calls the success block on the dispatch_get_main_queue or on the thread that called it - in this case the operation above.
Before the block is called, the method isFinished is actually returning true (I overrode the isFinished method and checked the value), so can someone explain me how is it possible that the block is being called?
I'm asking all this because although this works fine for one call, when I add it in a cycle of a few hundred iterations, I get an EXC_BAD_ACCESS and understanding the above might help me on the debugging.

The code inside the block will only be called when getStuff calls success or failure. I thought that in the meanwhile, my operation would be removed from the NSOperationQueue and the block wouldn't be called.
What leads you to believe this. A block is a closure, a self-contained block of code. It does not rely on the existence of some other object (the NSOperation in this case) in order to exist. You might want it to rely on that other object, but that's up to you to enforce. Ideally, I'd make getStufSuccess:failure: synchronous. If you can't you can use an NSCondition or call NSRunLoop methods to block the thread cheaply until it's done.
You also need to consider thread safety here. Your problem might not have to do with the operation going away, but your block doing something that isn't thread-safe.

Since getStuffSuccess:failure is asynchronous, you need to use a concurrent operation. Here is a helpful blog post:
http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/

If your -getStuffSuccess:failure doesn't block the thread (i.e. the method is asynchronous), then your -main will complete and your operationQueue may deallocate your operation before the success or failure blocks are called. You can block the thread by adding a:
while(notProcessed){
sleep(0.1);
//Make sure your success and failure functions update notProcessed BOOL
}
so that main never completes before you've had a chance to call the closures. Or just use a synchronous method. This is generally fine because you won't be on the UI thread anyways.

Related

In Objective-c is performSelector executed inline or is it posted for execution as a different event?

There are plenty of reasons why this matters. Here's a simple example if you weren't using ARC.
[instance performSelector:selector withObject:objectA];
[objectA release]; // Did the selector actually finish executing
// in the line above so everyone's done with objectA
// or did the selector merely get scheduled in the line
// above, and is yet to execute, so objectA had better
// not be released yet?
I've done some research and context clues seem to point to selector getting done inline. But I haven't seen any definitive statement anywhere I've looked, that states it gets executed inline.
performSelector:withObject: is executed synchronously (block until the method finished).
Use performSelector:withObject:afterDelay: to execute method asynchronously on main thread (return immediately and execute later).
Use performSelectorInBackground:withObject: to execute method asynchronously on background thread (return immediately and execute on different thread).
Note:
performSelector and its friends should be avoid because it is undefined behaviour if you use them on method with incompatible method signature.
The aSelector argument should identify a method that takes no arguments. For methods that return anything other than an object, use NSInvocation.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/index.html#//apple_ref/occ/intfm/NSObject/performSelector:
Did the selector actually finish executing in the line above so
everyone's done with objectA or did the selector merely get scheduled
in the line above, and is yet to execute, so objectA had better not be
released yet?
It doesn't matter, for memory management purposes. Memory management in Cocoa is local -- you only need to care what your function does; you don't need to know, and shouldn't care, what other functions do internally, to manage memory correctly (ignoring retain cycles). As long as you're done with your owning reference, you should release it. It doesn't matter to you if other people are done with it.
This is because, according to Cocoa memory management rules, any function which needs to store it for use beyond the function call is required to retain it and release it when it's done (because the function cannot assume that the object lives beyond the calling scope otherwise). Any function which uses an argument asynchronously (e.g. performSelector:withObject:afterDelay: etc.) does indeed retain the object and release it when it's done.
Alternately, think about it this way: How does ARC work? How does ARC know whether a function uses its argument synchronously or asynchronously? It doesn't. There is no annotation that tells the compiler whether a function uses something synchronously or asynchronously. Yet ARC does it correctly. That means you can too, without knowing whether the function uses its argument synchronously or asynchronously.

Does performBlockAndWait always done on the same thread [duplicate]

I have an NSManagedObjectContext declared like so:
- (NSManagedObjectContext *) backgroundMOC {
if (backgroundMOC != nil) {
return backgroundMOC;
}
backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
return backgroundMOC;
}
Notice that it is declared with a private queue concurrency type, so its tasks should be run on a background thread. I have the following code:
-(void)testThreading
{
/* ok */
[self.backgroundMOC performBlock:^{
assert(![NSThread isMainThread]);
}];
/* CRASH */
[self.backgroundMOC performBlockAndWait:^{
assert(![NSThread isMainThread]);
}];
}
Why does calling performBlockAndWait execute the task on the main thread rather than background thread?
Tossing in another answer, to try an explain why performBlockAndWait will always run in the calling thread.
performBlock is completely asynchronous. It will always enqueue the block onto the queue of the receiving MOC, and then return immediately. Thus,
[moc performBlock:^{
// Foo
}];
[moc performBlock:^{
// Bar
}];
will place two blocks on the queue for moc. They will always execute asynchronously. Some unknown thread will pull blocks off of the queue and execute them. In addition, those blocks are wrapped within their own autorelease pool, and also they will represent a complete Core Data user event (processPendingChanges).
performBlockAndWait does NOT use the internal queue. It is a synchronous operation that executes in the context of the calling thread. Of course, it will wait until the current operations on the queue have been executed, and then that block will execute in the calling thread. This is documented (and reasserted in several WWDC presentations).
Furthermore, performBockAndWait is re-entrant, so nested calls all happen right in that calling thread.
The Core Data engineers have been very clear that the actual thread in which a queue-based MOC operation runs is not important. It's the synchronization by using the performBlock* API that's key.
So, consider 'performBlock' as "This block is being placed on a queue, to be executed at some undetermined time, in some undetermined thread. The function will return to the caller as soon as it has been enqueued"
performBlockAndWait is "This block will be executed at some undetermined time, in this exact same thread. The function will return after this code has completely executed (which will occur after the current queue associated with this MOC has drained)."
EDIT
Are you sure of "performBlockAndWait does NOT use the internal queue"?
I think it does. The only difference is that performBlockAndWait will
wait until the block's completion. And what do you mean by calling
thread? In my understanding, [moc performBlockAndWait] and [moc
performBloc] both run on its private queue (background or main). The
important concept here is moc owns the queue, not the other way
around. Please correct me if I am wrong. – Philip007
It is unfortunate that I phrased the answer as I did, because, taken by itself, it is incorrect. However, in the context of the original question it is correct. Specifically, when calling performBlockAndWait on a private queue, the block will execute on the thread that called the function - it will not be put on the queue and executed on the "private thread."
Now, before I even get into the details, I want to stress that depending on internal workings of libraries is very dangerous. All you should really care about is that you can never expect a specific thread to execute a block, except anything tied to the main thread. Thus, expecting a performBlockAndWait to not execute on the main thread is not advised because it will execute on the thread that called it.
performBlockAndWait uses GCD, but it also has its own layer (e.g., to prevent deadlocks). If you look at the GCD code (which is open source), you can see how synchronous calls work - and in general they synchronize with the queue and invoke the block on the thread that called the function - unless the queue is the main queue or a global queue. Also, in the WWDC talks, the Core Data engineers stress the point that performBlockAndWait will run in the calling thread.
So, when I say it does not use the internal queue, that does not mean it does not use the data structures at all. It must synchronize the call with the blocks already on the queue, and those submitted in other threads and other asynchronous calls. However, when calling performBlockAndWait it does not put the block on the queue... instead it synchronizes access and runs the submitted block on the thread that called the function.
Now, SO is not a good forum for this, because it's a bit more complex than that, especially w.r.t the main queue, and GCD global queues - but the latter is not important for Core Data.
The main point is that when you call any performBlock* or GCD function, you should not expect it to run on any particular thread (except something tied to the main thread) because queues are not threads, and only the main queue will run blocks on a specific thread.
When calling the core data performBlockAndWait the block will execute in the calling thread (but will be appropriately synchronized with everything submitted to the queue).
I hope that makes sense, though it probably just caused more confusion.
EDIT
Furthermore, you can see the unspoken implications of this, in that the way in which performBlockAndWait provides re-entrant support breaks the FIFO ordering of blocks. As an example...
[context performBlockAndWait:^{
NSLog(#"One");
[context performBlock:^{
NSLog(#"Two");
}];
[context performBlockAndWait:^{
NSLog(#"Three");
}];
}];
Note that strict adherence to the FIFO guarantee of the queue would mean that the nested performBlockAndWait ("Three") would run after the asynchronous block ("Two") since it was submitted after the async block was submitted. However, that is not what happens, as it would be impossible... for the same reason a deadlock ensues with nested dispatch_sync calls. Just something to be aware of if using the synchronous version.
In general, avoid sync versions whenever possible because dispatch_sync can cause a deadlock, and any re-entrant version, like performBlockAndWait will have to make some "bad" decision to support it... like having sync versions "jump" the queue.
Why not? Grand Central Dispatch's block concurrency paradigm (which I assume MOC uses internally) is designed so that only the runtime and operating system need to worry about threads, not the developer (because the OS can do it better than you can do to having more detailed information). Too many people assume that queues are the same as threads. They are not.
Queued blocks are not required to run on any given thread (the exception being blocks in the main queue must execute on the main thread). So, in fact, sometimes sync (i.e. performBlockAndWait) queued blocks will run on the main thread if the runtime feels it would be more efficient than creating a thread for it. Since you are waiting for the result anyway, it wouldn't change the way your program functioned if the main thread were to hang for the duration of the operation.
This last part I am not sure if I remember correctly, but in the WWDC 2011 videos about GCD, I believe that it was mentioned that the runtime will make an effort to run on the main thread, if possible, for sync operations because it is more efficient. In the end though, I suppose the answer to "why" can only be answered by the people who designed the system.
I don't think that the MOC is obligated to use a background thread; it's just obligated to ensure that your code will not run into concurrency issues with the MOC if you use performBlock: or performBlockAndWait:. Since performBlockAndWait: is supposed to block the current thread, it seems reasonable to run that block on that thread.
The performBlockAndWait: call only makes sure that you execute the code in such a way that you don't introduce concurrency (i.e. on 2 threads performBlockAndWait: will not run at the same time, they will block each other).
The long and the short of it is that you can't depend on which thread a MOC operation runs on, well basically ever. I've learned the hard way that if you use GCD or just straight up threads, you always have to create local MOCs for each operation and then merge them to the master MOC.
There is a great library (MagicalRecord) that makes that process very simple.

Calling a block from within an inner block

I have a Cocoa/Objective-C class with a method that looks something like this:
- (void)doWork:(void (^)(void))handler
{
[self->someObject doActualWork:kWorkID handler:^(Result *result) {
if (handler)
handler();
}];
}
However, when the inner block is called handler have been dealloced and the program crashes when it is called. From what I understand this is because the block is stored on the stack and thus removed soon after doWork: finishes. I'm using ARC. What should I do to fix this?
First, self-> for iVar access is an odd, and discouraged, pattern, generally.
Did you copy the blocks prior to storing 'em away for use later? If this is intended to be asynchronous code, then your actualWork:handler: method should be copying the block prior to enqueueing it.
Even under ARC; while ARC handles the return of blocks from methods automatically, it can't handle blocks as arguments automatically and you do still need to copy 'em.
If this is purely synchronous code, then something else is going wrong. You'll need to provide more clues.

Objective C: Memory management in Block cases

I am wondering if I am using blocks as shown in the code below
__block Loader *loader = [[Loader alloc]initWithResourcePath:self.resourcePath];
[loader setCompletionHandler:^(NSArray *anArray){
self.answerArray=anArray;
[self reloadData];
}];
[loader getObjects];
My question is with regards to memory management. The analyzer tells me that there is a potential leak (since I did an alloc/init for my loader). How can I stop the leak here? I tried to release the loader at the end but that causes my app to stop functioning. Any advise is appreciated here
Several issues:
there is no reason for loader to be declared __block; you aren't re-assigning in the block and, thus, the __block is pointless.
the leak is because you alloc/init the loader, but never release it
do not name methods getSomething; the get prefix is reserved for methods that return stuff by reference. Just call it objects. If it is supposed to trigger the load, then call it load or performLoad.
If it is asynchronous, then getObjects is pointless. If synchronous, then the completion block is pointless.
If loader is to be used synchronously, release it at the end of the method. If it is asynchronous, then the completion block could release it. Note that the use of __block in this case is still pointless; while referring to loader in the completion block will create a retain cycle, it will be broken when you explicitly Block_release() the block in your loader (because you must have done a Block_copy() when setting the completion handler if it is to be used asynchronously in the first place).
If you plan to use loader outside of the function calling your block, it is highly possible that you need to store it in a ivar of your controller (I guess, it is a controller, but I don't know what kind of class owns the code you shows). Once you do that, you can release it in your dealloc.
The reasoning is that loader should live across several methods and runloop cycles, so a local variable will not do.
Otherwise, just release it at the end of the block, once you have done with it.
If this does not seem right to you, then possibly more code is needed.
I'm going to make some assumptions: 1) The completion handler (block) is used by method getObjects. 2) getObjects is asynchronous (it returns to the caller right away though it continues to process).
With these assumptions you can't send release after sending getObjects because getObjects is still using the completion handler.
Try sending a release or autorelease at the end of the completion handler. That should free loader provided reloadData is not also asynchronous.

NSOperation does not spawn a new thread?

I have a NSOperationQueue with a number of NSOperations in it. I want to ensure that a particular part of the code is not executed in parallel. I use a NSLock object like this:
[myLock lock]
some critical code
[myLock unlock]
Unfortunately instead of a blocking "lock" call I get the following error:
-[NSLock lock]: deadlock ( '(null)')
After some investigation I noticed that all NSOperations seem to run in the same thread. I drew that conclusion after logging the thread id with:
NSLog(#"Thread %#\n", self, [NSThread currentThread]);
All operations seem to run in the same thread. Even though they are running in parallel as operations.
Does that make sense? I am a little confused. Do I miss something? Do you see any problem with using NSOperation and NSLock together? (If not, then I am sure the error is in my code)
I solved it. I am using ASIHTTPRequest underneath. Apparently all HTTP calls are made in the same thread unless you override "+ (NSThread *)threadForRequest:(ASIHTTPRequest *)request".
Sorry.