First, Block introduction
Block is a C-language level statement, and the methods in C are similar. In some other languages, blocks are sometimes referred to as "closure" (closures). She can be declared as a pointer variable, passed as a parameter for the callback, and also very convenient on the asynchronous call;
Block is an anonymous, inline code collection that lists some of her features:
1. Parameter list as method
2, there is a return type
3. Can occupy state in the scope where it is declared
4, you can selectively change the state in its scope
5. Possibility to share changes with other blocks of code in the same scope
6, although its (stack) scope is destroyed, she can continue to share and change the state defined in the scope
Block is stored in the stack when it is created, similar to the method, but there is a possibility that the Yu Yu will be destroyed in its scope, so the block can be copied or passed to other threads to execute, and the copied block will exist in the heap, so that the original corresponding stack space is sold to the user, The block in the heap still works, which is invisible to the user, and the developer does not have to manually send the block_copy () message for replication, the runtime will do it automatically, and he will manage variables of various properties in the block, as described below.
Second, usage
1. Statement
The block declaration is similar to a method pointer, just replacing * with the ^
Form: return type (^ variable name) (parameter list)
The following is an example of a document declaring a block variable:
void (^blockreturningvoidwithvoidargument) (void); |
Int (^blockreturningintwithintandchararguments) (int, char); |
void (^arrayoftenblocksreturningvoidwithintargument[10]) (int); |
Of course, typedef is easier to use.
typedef float (^myblocktype) (float, float); |
|
Myblocktype Myfirstblock =//...; |
Myblocktype Mysecondblock =//...; |
2. Create
Form:
^ (parameter list) {
Body
};
If the argument is void, the (void) can be omitted, and the document example:
Float (^onefrom) (float); |
|
Onefrom = ^ (float afloat) { |
float result = aFloat-1.0; |
return result; |
}; |
3. Global block
In use, we often create a global block:
#import <stdio.h> |
|
int globalint = 0; |
Int (^getglobalint) (void) = ^{return globalint;}; |
Third, the variables in the block
The use of variables in code blocks are: Global variables (such as static modified variables), global methods (strictly not teach variables), local variables and parameters, __block modified variables, static introduction.
The documentation lists the rules for using variables in the BLOCK:
1. Accessible global variables, including static variables that exist in the block scope
2, access to the parameters of the block
3, the stack variable (non-static, that is, the ontology exists in the stack, such as int), when the program execution to the definition of the block will capture the value of the variable and as a const variable to use, equivalent to copy a const variable with the same name is used in the block.
4, local variables declared in the block scope, if the __block keyword is used in the declaration, then the change amount is writable in the block, otherwise it is readable. If more than one block uses the same variable of the __block type, the change is shared.
5, the local variables declared in the block, like the local variables declared in the method, feel free to use
The two examples of block using stack variables are given in the documentation:
1)
int x = 123; |
|
void (^printxandy) (int) = ^ (int y) { |
|
printf ("%d%d\n", x, y); |
}; |
x=789; This sentence is added, can be used as a reference |
Printxandy (456); Prints:123 456 |
2)
int x = 123; |
|
void (^printxandy) (int) = ^ (int y) { |
|
x = x + y; Error |
printf ("%d%d\n", x, y); |
}; |
There are also examples of __block situations:
1)
__block int x = 123; x lives in block storage |
|
void (^printxandy) (int) = ^ (int y) { |
|
x = x + y; |
printf ("%d%d\n", x, y); |
}; |
Printxandy (456); prints:579 456 |
2)
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 ' |
} |
The relationship between the object and the block variable is also described in the documentation. The block uses the object variable when it executes:
1. If the instance variable is accessed by reference, a strong reference will be directed to the self
2. If the instance variable is accessed by value, a strong reference will be directed to the variable
The following example shows two different scenarios:
Dispatch_async (Queue, ^{ |
Instancevariable is used by reference, a strong reference was made to self |
Dosomethingwithobject (instancevariable); |
}); |
|
|
ID localvariable = instancevariable; |
Dispatch_async (Queue, ^{ |
/* |
Localvariable is used by value, a strong reference are made to localvariable |
(and not to self). |
*/ |
Dosomethingwithobject (localvariable); |
}); |
Iv. use of block
If you declare a block as if you were declaring a variable, you can use her as you would with a method, and the document gives two examples:
Int (^onefrom) (int) = ^ (int anint) { |
return anInt-1; |
}; |
|
printf ("1 from-is%d", Onefrom (10)); |
Prints "1 from Ten is 9" |
|
Float (^distancetraveled) (float, float, float) = |
^ (float startingspeed, float acceleration, float time) { |
|
float distance = (Startingspeed * time) + (0.5 * acceleration * time * time); |
return distance; |
}; |
|
float Howfar = distancetraveled (0.0, 9.8, 1.0); |
Howfar = 4.9 |
We can pass the block as the parameter of the method, in many cases, where the block parameter is required, the block does not need to declare simply inline implementation, the inline implementation is like many other languages anonymous classes or anonymous methods, the creation of the same time directly used. Examples of documentation are as follows:
Char *mycharacters[3] = {"Tomjohn", "George", "Charles Condomine"}; |
|
Qsort_b (mycharacters, 3, sizeof (char *), ^ (const void *l, const void *r) { |
Char *left = * (char * *) L; |
Char *right = * (char * *) R; |
Return strncmp (left, right, 1); |
}); |
Block implementation ends at "}" |
|
Mycharacters is now {"Charles condomine", "George", "Tomjohn"} |
Five, the attention point
At this point I summarize the points of attention using code blocks:
1, avoid circular reference, if you define the block variable in self, and implement the block in the. Statement (the _ variable is also equivalent to a. variable), it will cause a circular reference. Please use __weak to modify self;
2, avoid suspending the pointer situation, because the block starts when the stack is stored, before being copied to the heap, it may cause the actual scope and variable scope and cause the variable to become a dangling pointer, the document gives two 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. |
} |
} |
|
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. |
} |
// ... |
} |
If you see a friend who is mistaken, please point out. Thank you
Introduction to IOS block, reference from official documentation