iOS development blocks detailed (GO) (2013-10-14-16:41:54)
Starting with Mac OS X 10.6 and iOS 4, Apple introduced a new extension to the C language in the GCC and clang compilers: Blocks, which allows programmers to use closures in C, objective-c, C + +, and objective-c. Blocks is a bit like a function, but it can be declared and defined in other functions or methods, and it is anonymous (anonymous), and can capture variables (closures) in its scope.
The syntax of blocks
The function pointers in blocks and C are somewhat similar, and if you know the function pointers you will find that blocks will be easy to master. The following are a C function pointer and a blocks declaration, respectively:
1 2 3 |
Int (*foo) (int, int); Int (^foo) (int, int); |
They all accept parameters of two int and return an int value, the only difference being that the * in the function pointer declaration becomes ^. According to Apple, ^ is chosen because it is the only operation symbol in C + + that cannot be overloaded. In addition, since both statements are too cumbersome, you can use typedef as an alias for the type as in C, which is handy for your code:
1 2 3) 4 5 |
typedef int (*FP) (int, int); Fp foo; typedef int (^block) (int, int); Block foo; |
Next look at how to define a block:
1 |
Block sum = int ^ (int x, int y) {return x + y;}; |
Where ^ marks this as a block definition, in front of which is the type of its return value, the parameters it accepts in parentheses, and the body of the block in {}. Since the compiler can automatically infer the return type of the block, the return type in front of the ^ can be omitted, and if the block does not accept any parameters, the part of the brackets can be omitted;
1 2 3 |
Block sum = ^ (int x, int y) {return x + y;} void (^bar) (void) = ^ {printf ("Hello world!\n");} |
Basic usage of blocks
Execute a block and call a C function like
In addition, a block in Objective-c is also an object, and it also has an Isa pointer to its class object. This means that you can send messages such as-copy,-release, and retain to it.
Blocks has a closure feature, so it can be used to capture variables in its scope:
1 2 3 4 5 6 7 8 9 10 11 |
void Testblock () {int a = 1; int b = 2; int (^ablock) (void) = ^ {return a + B;}; printf ("%d\n", Ablock ());//Output 3 A = 0; printf ("%d\n", Ablock ()); or Output 3} |
Note that the value of two outputs is 3, even before the second output we have assigned the value of a to 0. This is because the compiler has made a const copy of the values of A and B when defining Ablock (you cannot modify the value of a in Ablock) and save, resulting in subsequent external modifications to a that do not affect the execution results of Ablock. If you want to access a by reference in Ablock or modify the value of a, you need to precede the declaration of a with a qualifier __block:
1 2 3 4 5 6 7 8 9 |
void Testblock () {__block int a = 1; int b = 2; int (^ablock) (void) = ^ {return a + B;}; a = 0; printf ("%d\n", Ablock () ); Output 2} |
In this way, a variable that uses the qualifier is passed into the block by reference, so that its value can be modified after the block executes. Such variables are usually stored in the stack, but if the block referencing the variable is copied, it will be copied to the heap as well.
Blocks Memory Management
The code in the block is stored and loaded in the same way as normal functions, but it also requires additional space to hold the variables it captures, that is, the variable referenced in the block needs to be copied into its own private memory. When you declare that a block is defined, its private memory space is allocated to the stack. So by default, when the method or function that defines the block returns, the memory is invalidated. So when you need to return a block, you need to explicitly use Block_copy () (if the block is already in the heap, its retain count will be added 1) will be copied to the heap. Because block is also an object in Objective-c, you can also send-copy messages to achieve the same effect. Now that you have a copy of the process, you also need to call the Block_release () to perform the corresponding release operation, in the same way, you can send the-release message to the objective-c. One thing to note is that the following scenario also causes a block's private storage space to expire:
1 2 3 4 5 6 7 8 9 10 11 12 |
typedef void (^block) (void); void foo () {Block ablock, if (condition) {Ablock = ^ {...};} else {ablock = ^ {...}} ...//At this point Ablock has pointed to an invalid memory } |
As mentioned above, block is also an object in Objective-c, so you can send-copy,-retain,-copy and even-autorelease messages for corresponding memory management. However, in Objective-c, the block is a bit different, it will automatically retain the referenced NSObject object (these objects will also be release when the Block is destroyed), including other blocks. So you can also use this feature to make an object that is not inherited from NSObject automatically retain, by adding __attribute__ ((nsobject) to the object's declaration. It is important to note that if you are referencing an instance variable, it retain directly to self, which can sometimes result in a reference ring (two or more objects referencing each other directly or indirectly) and causing a memory leak. The workaround is to create a pointer to self when you need to access the instance variable in the block, and use the __block modifier on it so that it is not automatically retain:
1 2 3 4 5 6 |
-(void) foo {__block id blockself = self; ^ {blockself->bar = 3;}} |
Because the value of an object pointer using the __block modifier can be modified in a block, what if the block automatically retain the object to which the pointer is pointing, and when its pointer value is modified? And Apple's approach is simply not automatically retain it.
It is also important to note in Objective-c that although the Block object can accept-retain messages, it is ineffective to send the message to a block that exists in the stack. So, before you can save a blocks object to a dictionary or array, you need to perform the corresponding copy operation (because containers such as Nsarray or nsdictionary automatically retain the objects that are deposited). Similarly, sending a-copy message to a block that has been copied to a heap will not actually perform a copy, just add its reference count to 1, which means copying a block and recreating the same block is not the same, and the block created by the copy will share all declarations as __ Block variables, so if you want a brand new block, you need to recreate it once.
Summarize
Blocks is a very useful tool, and its closure feature can make the code more concise, such as the use of gcd such as the need to specify the callback API (but the use of GCD does not have to use blocks). Apple has added many APIs in the cocoa framework that use blocks, and you can encapsulate it with existing APIs to support blocks (such as blockskit) for ease of use.
iOS development blocks detailed (GO)