Thanks, Roland. I can see you are comparing the member variable currentOperation of the caller's class and a locally declared variable currentOperationAtQueueTime. Good idea. Obviously, the block retains "self" of the caller object and all local variables referenced from within the block. So when I call currentOperation I actually get self->currentOperation, which may change, and currentOperationAtQueueTime which is frozen. This makes the check possible
> operation.completionBlock = [ [ SomeMagicBlockObject alloc ] > initWithPrecompiledCode:(code)code environmentVar1:(id)var1 > environmentVar2:(id)var2 .. ]; Yes, it helps to understand blocks better. A block indeed consists of a piece of code (like a function pointer) and all retained/copied variables of the context. Basically, the definition of what an object is in OOP. On Sat, Mar 16, 2013 at 3:14 PM, Roland King <r...@rols.org> wrote: > > However, when I use completion blocks instead of delegates, things get > somewhat vague. > > Is it still necessary to store the current operation in a property, or > does each operation get its own independent copy of the completion > block, together with its current context? What happens if I create > another operation and launch it with its completion block - will the > first operation still fire the block when it's done? If so, how do I > > > Yes it still fires. > > correctly discard such call from a ditched operation? I tried to save > the current operation in a property, but then in the completion block, > I don't have anything to compare it with, as the completion block > doesn't provide a sender. Or should I always use blocks with sender as > a parameter? > > > if you want to do this you probably have to think about it the other way > around. Imagine in your class > which fires these things off you have a simple counter member variable, > 'currentOperation'. It's set to > 0 when you have no operation and you increment it each time you make a new > one. The code looks > like this (typed in mail) > > > currentOperation++; > NSUInteger currentOperationAtQueueTime = currentOperation; > > [ methods which enqueues:^{ > > // your block work here > > // then jump back to the main queue to call operationDidFinish: > dispatch_async( dispatch_get_main_queue() ) > { > if( currentOperation == currentOperationAtQueueTime ) > { > [ yourClass operationDidFinish ]; > currentOperation = 0; > } > } > } ] > > Here's the code *in the block* which is checking whether its captured > version of > currentOperation is the same as the current, currentOperation, if it is then > it executes > the callback and resets the currentOperation. If not, just just does > nothing. The checking code > you want now goes in the block, not in the operationDidFinish. Note the two > ways of > capturing currentOperation, the first gets the current value out of it and > captures that, > that's currentOperationAtQueueTime, the second is using currentOperation in > the block > which is equivalent to self->currentOperation, ie it's the value at the time > that completion > block runs. That's why it can compare them and know whether to run or not. > > > P.S. It seems that I don't quite understand the nature of blocks. On > one hand, they are objects, i.e. instances of some class, but on the > other hand they appear like pieces of code, so they are classes. When > I write something like operation.completionBlock = ^(){ // some code}; > do I create another instance of a block object or am I reusing the > same instance over and over again? Is such writing equivalent to a > object literal, like @"string" for strings? What is even more unclear, > what happens to the context of blocks, i.e. self and ivars of the > object where the block is declared, will that be the same retained > object in all operation instances' completion blocks? How about local > vars declared outside and used inside of the block - will they be > different or the same instances for each operation? > > > I'm not sure thinking about them as objects or classes helps. They are > 'objects' as > far as they can be retained and released and ARC can manage them, I'd not go > further > than that. > > The way I sometimes think about blocks to answer the second part of the > question is that I consider > the ^{ .. } denotes the time that the block's arguments are captured and > bound to the code > which was pre-compiled. So > > operation.completionBlock = ^{..}; > > makes a new block with the same code and the current freeze-dried > environment. Every time you call > > operation.completionBlock(); > > you will run that same code with the same captured environment until the > point you do > > operation.completionBlock = ^{ .. }; > > again at which point you'll capture the current environment again at the > point in your code that line > is executed. If you assign that block to something like this > > anotherOperation.completionBlock = operation.completionBlock; > > you really copy the block with its environment as it was when it was > created. > > I've found that thinking that the ^{..} actually creates an instance of the > block almost as if you > were doing something like > > operation.completionBlock = [ [ SomeMagicBlockObject alloc ] > initWithPrecompiledCode:(code)code environmentVar1:(id)var1 > environmentVar2:(id)var2 .. ]; > > helps me to think about blocks. That way of looking at it is pretty stupid, > isn't how it works and may not work for you, it does for me. > > > > > > _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com