Learning goals in this chapter:
1. Understand what block is.
2. Understand how block is used.
Block is an iOS new program syntax after 4.0, strictly speaking, the concept of block is not the scope of the basic program design, for beginners is not very easy to understand, but after iOS SDK 4.0, block appears in almost all the new API, in other words, If you don't understand the concept of block, you won't be able to use the new features of the SDK 4.0 version, so although the syntax of block itself is a bit difficult, we have to bite the bullet to understand the new programming concept in order to use the new features of iOS.
The goal in this chapter is to understand how to use block-based without delving into the workings of block bottom, as some beginners encounter fewer words such as "lexical scope (lexical scope)," and so on, this chapter will no longer explain, to interested readers to consult Google God.
X.1 on block
In this section we first use some simple examples to import the concept of block.
x.1.1 declaring and using block
We use the "^" operator to declare a block variable, and add ";" at the end of the block definition. To represent a complete statement (that is, to treat the entire block definition as a simple statement as described in the previous section, since the entire definition must be a complete sentence, and therefore must be preceded by a semicolon), here is an example of a block:
1:int multiplier = 7;
2:int (^myblock) (int) = ^ (int num)
3: {
4: return num * multiplier;
5:};
We use it to explain this example (please translate the words in the text box as follows):
We declare a "myblock" variable and use the "^" symbol to indicate that it is a block.
This is the complete definition of block, which will be assigned to the "myblock" variable.
Indicates that "myblock" is a block with a callback value of integer (int).
It has a parameter, and the pattern is also an integer.
The name of this parameter is called "num".
This is the contents of the block.
It is important to note that blocks can use the same variables that define the scope themselves, and you can imagine that in the example above, multiplier and myblock are all two variables defined within a function, and this variable is in the middle of a function two braces "{" and "}". Because their effective range is the same, the multiplier variable can be used directly in the block, and when the block is defined as a variable, we can use it directly as a general function:
1:int multiplier = 7;
2:int (^myblock) (int) = ^ (int num)
3: {
4: return num * multiplier;
5:};
6:printf ("%d", Myblock (3));
7://Results will print out 21
x.1.2 Direct use of block
In many cases, we do not need to declare the block as a variable, whereas we can directly write the block's contents directly in the place where we need to use block, in the following example Qsort_b function, which is a similar traditional qsort_t function, But use block directly as its parameter:
1:char *mycharacters[3] = {"Tomjohn", "George", "Charles Condomine"};
2:qsort_b (Mycharacters, 3,
3: sizeof (char *),
4: ^ (const void *l, const void *r)//block part
5: {
6: Char *left = * (char * *) L;
7: Char *right = * (char * *) R;
8: return strncmp (left, right, 1);
9: } //end
10:);
x.1.3 __block Variable
In general, only variables in the same scope can be read within the block and there is no way to modify any variables defined outside the block, and if we want these variables to be modified in the block, we must hang the __block modifier in front of it, in the first example above Multiplier, this variable in the block is read-only, so multiplier = 7 after the specified, in the block multiplier can only be 7 can not be modified, if we modify the multiplier in the block, the editor will Generates an error, so if you want to modify multiplier in a block, you must precede the multiplier with the __block modifier, see the following example:
1: __block int multiplier = 7;
2:int (^myblock) (int) = ^ (int num)
3: {
4: if (num > 5)
5: {
6: multiplier = 7;
7: }
8: Else
9: {
Ten: multiplier = 10;
One: }
: return num * multiplier;
: };
X.2 Block Overview
Block provides us with a way to embed function code in a general sentence, and in other languages there are similar concepts called "closure", but in order to match Objective-c's example, we call this usage "block"
function of x.2.1 Block
Block is an inline function with anonymous functionality, which has the following characteristics:
As a general function can have parameters with the form.
Has a callback value.
The defined lexical scope (lexical scope) state can be retrieved.
You can optionally modify the state of the lexical scope.
Note: The lexical scope (lexical scope) can be imagined as a block in the middle of a function of two braces, which, when executed, will put this chunk into a stacked memory, and the declared variables in this block are like the area variables we often hear. When we say that block can retrieve the state of the same lexical scope, you can imagine that the block variable and other regional variables are the same level of regional variables (in the same layer of the stack), and the contents of the block can be read to other regional variables at his level.
We can either copy a block or throw it into another thread, basically although block can be used in the development of iOS programming, it can also be used in objective-c, but in the definition of the system, Block will always be considered a Objective-c object.
x.2.2 Block's use time
Blocks are typically used to represent and simplify a small piece of code, which is particularly well-suited for creating some program fragments that are executed synchronously, encapsulating small jobs, or calling back paging (callback) when a job is completed.
Blocks are heavily used to replace traditional delegate and callback in the new iOS API, and the new API will be heavily used for blocks based on the following two reasons:
You can write directly in the code, and so on to execute the program, directly the code into the function of the parameters passed into the function, which is the new API most commonly used block.
can access the regional variables, in the traditional callback implementation, if you want to access the region variable to be encapsulated in a variable structure to use, and block is convenient to directly access the regional variables.
X.3 Declaration and establishment of block
x.3.1 Declaration block Reference (Reference)
The block variable stores a block reference, and we declare it in a way similar to the declaration indicator, where the block variable refers to a function, and the indicator uses "*",block to declare it using "^", and here are some valid block declarations:
1:/* callback void, parameter is void block*/
2:void (^blockreturningvoidwithvoidargument) (void);
3:/* callback integer, two parameters are integers and character block*/
4:int (^blockreturningintwithintandchararguments) (int, char);
5:/* return void, array containing 10 blocks, each block has a parameter of type integer */
6:void (^arrayoftenblocksreturningvoidwinintargument[) (int);
11:int (^onefrom) (int); /* DECLARE block variable */
*/ * Define the contents of the block and assign to the variables declared above */
: onefrom = ^ (int anint)
: {
15:
: };
x.3.3 Whole-domain block
I can declare a whole domain block in the file, please refer to the following example:
1:int globalint = 0;
2:int (^getglobalint) (void) = ^ (void) {return globalint;};
X.4 Block and variables
In the next section we will describe the interaction between block and variable.
Patterns of x.4.1 variables
We can encounter the types of variables that we normally encounter in a function block:
The global variable, or static local variable.
L whole-domain functions.
L Regional variables and parameters passed in by the enclosing domain (enclosing scope).
In addition to the above, the block supports two additional variables:
__block variables can be used within a function, and these variables can be modified in the block.
The import constant (const imports).
In addition, in the implementation of the method, the block can use the OBJECTIVE-C entity variable (instance variable).
The following rules apply to the use of variables in the block:
You can access global variables and static variables in the same domain (enclosing lexical scope).
You can access the parameters of the incoming block (in the same way as the parameters passed in the function).
Regional variables in the same domain will be treated as constants (const) in the block.
You can access variables that use __block as modifiers in the same field.
The area variables declared in the block are used in the same way as the normal function using the regional variables.
The following example shows how a zone variable (3rd above) is used:
1:int x = 123;
2:void (^printxandy) (int) = ^ (int y)
3: {
5: };
6://will be printed 123 456
7: Printxandy (456);
10:int x = 123;
11:void (^printxandy) (int) = ^ (int y)
12: {
All: //The following line is wrong, because X is a constant in this cannot be modified.
: x = x + y;
15:
: };
If you want to modify the above variable x in the block, you must add the X declaration plus the modifier word __block, please refer to the next section for an introduction.
x.4.2 __block Type variables
We can make this variable from read-only to readable and write by placing a variable that is imported into block from the outside, but one limitation is that the variable passed in memory must be a variable that occupies a fixed-length memory, __ Block modifiers cannot be used for variable-length variables such as variable-length arrays, refer to the following example:
1://plus __block modifier, so it can be modified in block.
2: __block int x = 123;
3:void (^printxandy) (int) = ^ (int y)
4: {
5:
7: };
8://will be printed 579 456
9: Printxandy (456);
Ten://x will become 579;
13:extern Nsinteger Counterglobal;
14:static Nsinteger counterstatic;
15: {
16:nsinteger localcounter = 42;
: __block char Localcharacter;
18:void (^ablock) (void) = ^ (void)
: {
: + + Counterglobal;//can be accessed.
+: + + counterstatic;//can be accessed.
22:counterglobal = Localcounter; The localcounter is immutable when the block is built.
localcharacter = ' a ';//Set the Localcharacter variable defined outside.
: };
: ++localcounter;//The value in the block that will not be affected.
: localcharacter = ' B ';
: Ablock ();//execute block contents.
28://After execution, Localcharachter will become ' a '
29:}
x.4.3 objects and block variables
Block support is used as a variable in objective-c, C + + objects, and other blocks, but because in most cases we use Objective-c's writing program, we only introduce objective-c in this section, As for the other two cases, it is left to interested readers to go further into their own.
x.4.3.1 Objective-c Objects
In an environment that has a reference count (reference-counted), if we refer to the Objective-c object in the block, it will automatically increase the reference count of the object in general, but if the object with the __block modifier is not affected by the reference count.
If we use block in the Objective-c method, the following few and memory management things require additional attention:
L IF the entity variable is accessed directly (instance variable), the reference count of self will be added 1.
If the value of the entity variable is accessed through a variable, the reference count of the variable will be added 1.
The following code illustrates the above two cases, where the hypothesis instancevariable is a solid variable:
1:dispatch_async (Queue, ^{
2://Because the direct Access entity variable instancevariable, so self retain count will add 1
3:dosomethingwithobject (instancevariable);
4: });
5:id Localvaribale = instancevariable;
6:dispatch_async (Queue, ^{
7://localvariable is the access value, so only localvariable retain count plus 1
8: The return count of//self is not incremented.
9:dosomethingwithobject (Localvaribale);
: });
X.5 using block
In this section we will make a preliminary introduction to how block is used.
x.5.1 Call a block
When block is declared as a variable, we can use it as a general function, see the following two examples:
1:int (^onefrom) (int) = ^ (int anint) {
2:return anInt-1;
3: };
4:printf ("1 from Ten is%d", Onefrom (10));
5://Results are shown: 1 from 9
6:float (^distancetraveled) (float, float, float) = ^ (float startingspeed, float acceleration, float time)
7: {
8:float distance = (Startingspeed * time) + (0.5 * acceleration * time * time);
9:return distance;
Ten: };
11:float Howfar = distancetraveled (0.0, 9.8, 1.0);
//howfar will become 4.9
In common cases where block is used as a parameter pass-through function, we usually use the block in an "inline" manner.
x.5.2 block as an argument to a function
We can use the general function as a parameter, the block in the function parameters of the type into the function, in this case, most of the way we use block will not tend to declare block, but directly embedded in the way to the block, this is the current version of the SDK mainstream approach, We will add examples from the previous chapters to illustrate:
1:char *mycharacters[3] = {"Tomjohn", "George", "Charles Condomine"};
2:qsort_b (mycharacters, 3, sizeof (char *),
3: ^ (const void *l, const void *r)
4: {
5:char *left = * (char * *) L;
6:char *right = * (char * *) R;
7:return strncmp (left, right, 1);
8: }//This is the end of block.
9: );
10://The final result is: {"Charles condomine", "George", "Tomjohn"}
In the example above, the block itself is part of the function parameter, and in the next example the Dispatch_apply function uses the block,dispatch_apply definition as follows:
1:void
2:dispatch_apply (size_t iterations, dispatch_queue_t queue, void (^block) (size_t));
5:size_t count = 10;
6:dispatch_queue_t queue =
7:dispatch_get_global_queue (dispatch_queue_priority_default, 0);
8:dispatch_apply (count, queue, ^ (size_t i) {
9:printf ("%u\n", I);
: });
x.5.3 block as a parameter to a method
There are many ways to use block in the SDK, and we can pass the block in a way that passes general parameters, and this example shows how to get the index value of the data we want in the first 5 data of an array:
1://All the information
2:nsarray *array = [Nsarray arraywithobjects: @ "A", @ "B", @ "C", @ "a", @ "B", @ "Z", @ "G", @ "is", @ "Q", nil];
3://We just need the information in this set.
4:nsset *filterset = [Nsset setwithobjects: @ "A", @ "B", @ "Z", @ "Q", nil];
5:bool (^test) (id obj, Nsuinteger idx, BOOL *stop);
6:test = ^ (id obj, Nsuinteger idx, BOOL *stop) {
7://Check only the first 5 data
8:if (IDX < 5) {
9:if ([Filterset containsobject:obj]) {
10:return YES;
One: }
: }
13:return NO;
14:};
15:nsindexset *indexes = [array indexesofobjectspassingtest:test];
16:nslog (@ "Indexes:%@", indexes);
17://Result: Indexes: <nsindexset:0x6101ff0>[number of Indexes:4 (in 2 ranges), indexes: (0-1 3-4)]
18:///Top 5 data, 4 are eligible, their index values are 0-1, 3-4
x.5.4 How to use this avoidance
In the example below, block is the zone variable for the for loop, so it must be avoided to designate the block of the zone to the outside declared block:
1://This is the wrong example, do not use these syntax in the program!!
2:void Dontdothis () {
3: void (^blockarray[3]) (void);//array of 3 blocks
4: For (int i = 0; i < 3; ++i) {
5: Blockarray[i] = ^{printf ("Hello,%d\n", i);};
6: //NOTE: This block definition is valid only for the For loop.
7: }
8:}
9:void Dontdothiseither () {
Ten: Void (^block) (void);
One: int i = random ():
: if (i > 1000) {
block = ^{printf ("Got I at:%d\n", i);};
: //NOTE: This block definition is only valid in two curly braces after the IF.
: }
: //...
17:}