Re: Callbacks from async blocks
Re: Callbacks from async blocks
- Subject: Re: Callbacks from async blocks
- From: Roland King <email@hidden>
- Date: Sat, 16 Mar 2013 21:14:35 +0800
> 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 (email@hidden)
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:
This email sent to email@hidden