Re: Callbacks from async blocks
Re: Callbacks from async blocks
- Subject: Re: Callbacks from async blocks
- From: Oleg Krupnov <email@hidden>
- Date: Sat, 16 Mar 2013 16:19:03 +0200
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 <email@hidden> 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 (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