It is said in apple's documents: A block literal (that is, ^{ ... }) is the address of a stack-local data structure that represents the block. The scope of the stack-local data structure is therefore the enclosing compound statement, so you should avoid the patterns shown in the following examples:
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop.
}
//for example I invoke the block here
blockArray[1]();
}
void dontDoThisEither() {
void (^block)(void);
int i = random():
if (i > 1000) {
block = ^{ printf("got i at: %d\n", i); };
// WRONG: The block literal scope is the "then" clause.
}
// ...
}
I don't know what patterns I should avoid. It seems like that I could invoke the block at which has the same literal scope as the block definition, for example behind the "if" or "for" statement. Could you please help me to explain it?
Here it is the link https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1
Blocks are a language-level feature added to C, Objective-C and C++, which allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary .
I think an analogy to pointers is as following.
void foo() {
int *block = NULL;
{
int a;
block = &a;
}
// `block`, even though defined here, points to
// an invalid memory address.
}
Generally, the block literal itself only exists in the block it is defined in, so when leaving that block, the literal disappears (like the variable a
did in the example above), and you're left with a dangling pointer.
For this reason, blocks are usually copied into the heap for future use. Non-ARC code uses block_copy
and friends. Copying into the heap also captures all relevant variables your block uses (which might create retain-cycles).
In practice, all of this is quite shunned away by the use of ARC, properties and classes. You define a copy
property in your class, and then just assign blocks to it. If you let the compiler generate the getter/setter, your block literal will automatically be copied into the heap.
@interface Bla : NSObject
@property (nonatomic, copy) void (^blockProperty)(int i);
@endf
...
Bla *bla = [[Bla alloc] init];
{
bla.blockProperty = ^(int i) { printf("%d", i); };
}
// bla.blockProperty now points to a heap copy of the block literal from above,
// so it's not dangling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With