So thanks to this post, I'm familiar with the __block keyword.
It basically means to NOT copy the instance, but rather just passing its original reference.
The benefits I see for doing that are:
Any modification made to the instance inside the block will reflect in the original instance.
Avoiding the "waste" of copying the instance we're gonna use inside the block.
I am curious, though, how much should we really bother with this declaration, for example, if I have this method that receives a callback block as a parameter:
-(void)doSomethingWithCallback:(MyTypeOfCallback)callback;
and let's say this method calls another method with a callback as a parameter. Is it then worthwhile to __block the original callback parameter if we want to call it inside the next method:
-(void)doSomethingWithCallback:(MyTypeOfCallback)callback
{
__block MyTypeOfCallback blockCallback = callback;
[self doAnotherThingWithBlock:^(BOOL result) {
if (result)
blockCallback();
}];
}
or should I simply call the original block parameter inside the next method?
-(void)doSomethingWithCallback:(MyTypeOfCallback)callback
{
[self doAnotherThingWithBlock:^(BOOL result) {
if (result)
callback();
}];
}
I'm asking because it makes sense to include the __block option, but then again I find myself doing it in too many places and it's starting to take many code lines.
BTW, this also goes for every any other type of parameter, not only blocks.
It's basically telling the compiler to NOT copy the instance
No. __block has nothing to do with "instances". __block is a storage qualifier for variables.
__block on a variable means that the same copy of the variable will be shared between the original scope any any blocks that capture it (as opposed to each block getting a separate copy of the variable when it captures non-__block variables).
In your case, you have a variable of type MyTypeOfCallback, a (I'm guessing) pointer-to-block type. In the first piece of code, you make it __block, so there is a single pointer variable whose state is shared between the function scope and the block (which captures it). If either scope assigns to the pointer variable, the change would be visible in the other scope.
In the second piece of code, you make it non-__block, and when the block literal is executed, it copies the value of that pointer at that moment into a separate pointer variable in its own structure, so that you have two copies of the pointer. If you afterwards assign to the pointer variable in the function scope, the change would not be visible to the block, since it has its own copy.
In this case, there is no difference between the two, because you never assign to the pointer variable in question after initialization. It is basically a constant variable, and one copy or two copies makes no difference.
-(void)doSomethingWithCallback:(MyTypeOfCallback)callback
{
__block MyTypeOfCallback blockCallback = callback;
[self doAnotherThingWithBlock:^(BOOL result) {
if (result)
blockCallback();
}];
}
You can call callback from in block so
-(void)doSomethingWithCallback:(void(^)(void))callback
{
__block typeof(callback)blockCallback = callback;
[self doAnotherThingWithBlock:^(BOOL result) {
if (result)
blockCallback();
}];
}
Related
Is it possible to define a block after passing it to a method? I want to do this so the code is in somewhat the order it runs in:
// Declare the block
void (^doStuffBlock)(void);
// Pass the block.
[self prepareToDoStuffWithCompletion:doStuffBlock];
// Define the block.
doStuffBlock = ^void() {
// Do stuff
};
doesn't work because inside prepareToDoStuffWithCompletion: the block doStuffBlock is nil.
you should first define the block then pass it to the method:
// Declare the block
void (^doStuffBlock)(void);
// Define the block.
doStuffBlock= ^void() {
// Do stuff
};
// Pass the block.
[self prepareToDoStuffWithCompletion:doStuffBlock];
You could use a typedef.
typedef void (^TypeName)(void);
- (void)bar:(TypeName)completion {
completion();
}
TypeName foo = ^() { /*...*/ };
[self bar:foo];
(My obj-c syntax might be a little rusty, but what you want to do is possible in both Objective-C and Swift.
https://stackoverflow.com/a/29580490/620197
http://goshdarnblocksyntax.com/
If you are certain that the method will run your doStuffBlock after you "define" it, what you could do is have your doStuffBlock capture a variable holding a second block with the real logic of what it should do. You can set the real-logic block after you create doStuffBlock, and you need to make sure that the variable holding the real-logic block is a __block variable, so that changes to the variable in the function scope are seen in the block scope.
__block void (^realLogicBlock)(void);
[self prepareToDoStuffWithCompletion:^{
if (realLogicBlock)
realLogicBlock();
}];
realLogicBlock = ^void() {
// Do stuff
};
You might have to be careful about retain cycles though -- if inside realLogicBlock, you capture a reference to self or to something that will reference the prepareToDoStuffWithCompletion: completion handler, you would have a retain cycle, in which case you may have to introduce a weak reference somewhere.
If you supply the completion handler closure, you are effectively saying “here is the closure I want you to use”.
If you are going to supply the closure later you would probably define a property:
#property (nonatomic, copy, nullable) void (^doStuff)(void);
Then, do not supply the closure when you call the method, but rather refer to this property:
- (void)prepareToDoStuff {
[self somethingAsynchronousWithCompletion:^{
if (self.doStuff) {
self.doStuff();
// if completion handler, you’d often release it when done, e.g.
//
// self.doStuff = nil;
}
}];
}
And, then you can call this method and supply the closure later:
[self prepareToDoStuff];
self.doStuff = ^{
NSLog(#"do stuff done");
};
A few additional considerations:
Make sure you synchronize your access to this doStuff property. E.g., in the above, I am assuming that the somethingAsynchronousWithCompletion is calling its completion handler on the main thread. If not, synchronize your access (like you would any non-thread-safe property in a multithreaded environment).
There is a logical race if you first call the method that will eventually call the block, and only later set that block property. Sometimes that is perfectly fine (e.g. maybe you are just trying to specify what UI to update when the asynchronous process finishes). Other times, the race can bite you. It depends upon the functional intent of the block property.
I would give the block property a name that better reflects its functional purpose (e.g. completionHandler or notificationHandler or didReceiveValue or whatever).
I want to simulate the NSAlert member function which only exist on 10.9.
- (void)beginSheetModalForWindow:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
The code is as following:
-(void)compatibleBeginSheetModalForWindow: (NSWindow *)sheetWindow
completionHandler: (void (^)(NSInteger returnCode))handler
{
void *handlerValue = (__bridge void*) [handler copy];
[self beginSheetModalForWindow: sheetWindow
modalDelegate: self
didEndSelector: #selector(blockBasedAlertDidEnd:returnCode:contextInfo:)
contextInfo: handlerValue];
}
-(void)blockBasedAlertDidEnd: (NSAlert *)alert
returnCode: (NSInteger)returnCode
contextInfo: (void *)contextInfo
{
void(^handler)(NSInteger) = (__bridge typeof(handler)) contextInfo;
handler(returnCode);
[handler release];
}
I need to copy the handler before cast it to void*, else it will crash, if I change it to following line:
void *handlerValue = (__bridge void*) handler;
And by check the handler in blockBasedAlertDidEnd:returnCode:contextInfo:, it is an incorrect value.
Even I call [handler retain] before cast to void* it doesn't work.
It is quite confuse to me, so why I need to copy it?
This is because blocks are created on the stack and not the heap. So when the stack pointer moves on the memory in that stack frame is returned and the block is lost. Thats why you always should copy blocks and not retain them. When you run copy on a block the new copy is allocated on the heap and therefor don't get removed.
Peter Segerblom covered the basics of it. In the current implementation, there are 3 kinds of blocks. Blocks that don't capture local variables are global blocks; there is just one instance that has static lifetime. Blocks that do capture local variables start out as objects on the stack; and copying it will return a block on the heap. Copying heap or global blocks will simply return the same instance.
Basically, a block passed into your function could be a stack block or not. A stack block is only valid for the current function call. Since it could be a stack block, you must use a copy of it if you want to store it somewhere that outlives the current function call. This is the contract for functions that take a block parameter.
Now, if all your function does with this block is pass it to another function, do you need to pass a copy? If this function parameter is of block type, then no, because if this function needs to keep the block around for later, then it is responsible for copying it (according to the contract above). So you don't need to worry about it. But, if you pass it to a function that is not of block type (e.g. -[NSMutableArray addObject:]), then that function does not know to potentially copy it (it doesn't even know it's a block). In that case, you will have to pass a copy if that function keeps the object around for later. This is the case with the function you are passing to here.
I'm trying to write a category based on node.js EventEmitter, which can take a number of blocks, store them weakly in an array, and execute them later if the instance creating the block isn't deallocated (in which case they would be removed from the array). This is in order not to keep filling the array with old, unused blocks.
The problem is that the blocks seem to be copied by the class, and thusly never released, even though the instance creating the block is deallocated.
So the implementation looks something like this;
Usage
[object on:#"change" do:^(id slf, NSArray *args) {
NSLog(#"something changed");
}];
Implementation (WeakReference class found here, courtesy of noa)
- (void)on:(NSString *)eventType do:(Callback)callback
{
NSMutableArray *callbacks = self.emitterEvents[eventType];
__weak Callback wcb = callback;
// Wrap the callback in NSValue subclass in order to reference it weakly
WeakReference *cbr = [WeakReference weakReferenceWithObject:wcb];
callbacks[callbacks.count] = cbr;
}
- (void)emit:(NSString *)eventType withArgs:(NSArray *)objArgs
{
NSInteger idx = 0;
NSMutableIndexSet *indices = [NSMutableIndexSet indexSet];
callbacks = (NSMutableArray *)callbacks;
for (WeakReference *cbv in callbacks) {
__weak id cb = [cbv nonretainedObjectValue];
if (cb) {
Callback callback = (Callback)cb;
__weak id slf = self;
callback(slf, objArgs);
} else {
[indices addIndex:idx];
}
idx++;
}
[callbacks removeObjectsAtIndexes:indices];
}
I read something about blocks being copied when used past their scope, but frankly, reading about all these block semantics is kind of making my head spin right now.
Is this way of approaching the problem even possible?
In Objective-C, blocks are objects, but unlike other objects, they are created on the stack. If you want to use the block outside of the scope it was created you must copy it.
[object on:#"change" do:^(id slf, NSArray *args) {
NSLog(#"something changed");
}];
Here, you are passing a pointer to a block on the stack. Once your current stack frame is out of scope, your block is gone. You could either pass a copy to the block, making the caller the owner of the block, or you could copy the block in the receiver.
If you want the caller to own the block, then you have to keep a strong reference to the block in the caller (e.g. as a property). Once the caller gets deallocated, you lose your strong reference and your weak reference is set to nil.
copy a block which is already copied is same as retain it, so if the caller of the method copy the block first then pass it to the method, it should works as you expected. but this means you cannot simply use the method as you described in your usage section.
you have use it like this
typeofblock block = ^(id slf, NSArray *args) {
NSLog(#"something changed");
};
self.block = [block copy]
[object on:#"change" do:self.block];
to actual solve the problem, you have to figure out owns the block. the caller of on:do:, or the object been called?
sounds to me you want to remove the block when the caller is deallocated, which means the owner of the block is the caller. but your on:do: method does not aware the owner of the block, and cannot remove the block when the caller is deallocated.
one way is to pass the owner of the block into the method and remove the block when it deallocated. this can be done use associate object.
- (void)on:(NSString *)eventType do:(Callback)callback sender:(id)sender
{
// add the block to dict
// somehow listen to dealloc of the sender and remove the block when it is called
}
another way is to add new method to remove the block, and call the method in dealloc or other place to remove the block manually.
your approach is similar to KVO, which require the observer to unregister the observation, and I think is a good practice that you should follow.
Thanks for the answers, I realize I was a little bit off on how blocks are managed. I solved it with a different approach, inspired by Mike Ash's implementation of KVO with blocks & automatic dereferencing, and with xlc's advice on doing it in dealloc.
The approach is along the lines of this (in case you don't want to read the whole gist):
Caller object assigns listener to another object with on:event do:block with:caller
Emitter object creates a Listener instance, with a copy of the block, reference to emitter & the event-type
Emitter adds the copied block to an array inside a table (grouped by event-types), creates an associated object on the caller and attaches the listener
Emitter method-swizzles the caller, and adds a block to its dealloc, which removes itself from the emitter
The caller can then choose to handle the listener-instance, which is returned from the emit-method, if it wants to manually stop the listener before becoming deallocated itself
Source here
I don't know if it is safe for use, I've only tested it on a single thread in a dummy-application so far.
To an id-variable, I can assign a block and call it afterwards; with an opaque pointer id this doesn't work (EXC_BAD_ACCESS).
In RestKit, the userData-object is an "opaque pointer"; now, I'd like to assign a block variable to it to call this block after the request finished. But because of this EXC_BAD_ACCESS it doesn't work. Is there a chance to user this opaque pointer to assign a block to it?
Thanks a lot!
EDIT:
// this works
id testId = ^{
NSLog(#"hello");
};
testId();
// this doesn't - but it's important to know RestKit
void (^postNotification)(void) = objectLoader.userData // EXC_BAD_ACCESS
postNotification();
objectLoader is of type RKObjectLoader (subclass of RKRequest), and the API says about userData: An opaque pointer to associate user defined data with the request.
You need to show us how you're creating the block and assigning it to userData to be sure, but my guess is you're not copying the block and it's going out of scope, like this:
objectLoader.userData = ^{ ... };
A blocks are created on the stack. That means when the compound statement (e.g. function) enclosing it ends, the block is no longer valid. If you want the block to survive, you need to copy it to the heap:
objectLoader.userData = [^{ ... } copy];
What exactly does the __block keyword in Objective-C mean? I know it allows you to modify variables within blocks, but I'd like to know...
What exactly does it tell the compiler?
Does it do anything else?
If that's all it does then why is it needed in the first place?
Is it in the docs anywhere? (I can't find it).
It tells the compiler that any variable marked by it must be treated in a special way when it is used inside a block. Normally, variables and their contents that are also used in blocks are copied, thus any modification done to these variables don't show outside the block. When they are marked with __block, the modifications done inside the block are also visible outside of it.
For an example and more info, see The __block Storage Type in Apple's Blocks Programming Topics.
The important example is this one:
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
// localCharacter now 'a'
}
In this example, both localCounter and localCharacter are modified before the block is called. However, inside the block, only the modification to localCharacter would be visible, thanks to the __block keyword. Conversely, the block can modify localCharacter and this modification is visible outside of the block.
#bbum covers blocks in depth in a blog post and touches on the __block storage type.
__block is a distinct storage type
Just like static, auto, and volatile, __block is a storage type. It
tells the compiler that the variable’s storage is to be managed
differently....
However, for __block variables, the block does not retain. It is up to you to retain and release, as needed.
...
As for use cases you will find __block is sometimes used to avoid retain cycles since it does not retain the argument. A common example is using self.
//Now using myself inside a block will not
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;
When you don't use __block, the block copies the variable (call-by-value), so even if you modify the variable elsewhere, the block doesn't see the changes.
__block makes the blocks keep a reference to the variable (call-by-reference).
NSString* str = #"hello";
void (^theBlock)() = ^void() {
NSLog(#"%#", str);
};
str = #"how are you";
theBlock(); //prints #"hello"
In these 2 cases you need __block:
If you want to modify the variable inside the block and expect it to be visible outside:
__block NSString* str = #"hello";
void (^theBlock)() = ^void() {
str = #"how are you";
};
theBlock();
NSLog(#"%#", str); //prints "how are you"
If you want to modify the variable after you have declared the block and you expect the block to see the change:
__block NSString* str = #"hello";
void (^theBlock)() = ^void() {
NSLog(#"%#", str);
};
str = #"how are you";
theBlock(); //prints "how are you"
__block is a storage qualifier that can be used in two ways:
Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).
In MRC, __block can be used to avoid retain object variables a block captures. Careful that this doesn't work for ARC. In ARC, you should use __weak instead.
You can refer to apple doc for detailed information.
__block is a storage type that is use to make in scope variables mutable, more frankly if you declare a variable with this specifier, its reference will be passed to blocks not a read-only copy for more details see Blocks Programming in iOS
hope this will help you
let suppose we have a code like:
{
int stackVariable = 1;
blockName = ^()
{
stackVariable++;
}
}
it will give an error like "variable is not assignable" because the stack variable inside the block are by default immutable.
adding __block(storage modifier) ahead of it declaration make it mutable inside the block i.e __block int stackVariable=1;
From the Block Language Spec:
In addition to the new Block type we also introduce a new storage qualifier, __block, for local variables. [testme: a __block declaration within a block literal] The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static.[testme] Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable. An implementation may choose an optimization where the storage is initially automatic and only "moved" to allocated (heap) storage upon a Block_copy of a referencing Block. Such variables may be mutated as normal variables are.
In the case where a __block variable is a Block one must assume that the __block variable resides in allocated storage and as such is assumed to reference a Block that is also in allocated storage (that it is the result of a Block_copy operation). Despite this there is no provision to do a Block_copy or a Block_release if an implementation provides initial automatic storage for Blocks. This is due to the inherent race condition of potentially several threads trying to update the shared variable and the need for synchronization around disposing of older values and copying new ones. Such synchronization is beyond the scope of this language specification.
For details on what a __block variable should compile to, see the Block Implementation Spec, section 2.3.
It means that the variable it is a prefix to is available to be used within a block.