From: http://iosdevelopersnote.blogspot.com/2010/11/block.html
Blockapple adds Block Extension usage in C, objective-C, C ++. Currently, only Mac 10.6 and iOS 4 are supported. A block is composed of a bunch of executable programs. You can also perform a function without a name (anonymous function ). For Mac 10.6 or IOS 4.0 platforms, the http://code.google.com/p/plblocks/ project can be used to support the block routing method.
Apple has a new function called Grand Central dispach, which is used in a concurrency environment for better efficiency. The block generator method produces a mechanism from GCD, which uses block to package a workload to GCD, and GCD has a macro program to allocate CPU and GPU resources, the best decision for memory.
Block Encryption
Block actually acts like a function. The biggest difference is that the variable value of the same scope can be accessed.
The block will grow like this
^ (Batch input data column) {row as main body };
The block is started with "^", followed by the number columns (for example, int A, int B, float c) wrapped by the small-inclusive dataset ), the main body of the behavior is enclosed by a large volume. The famous term is block literal. The row indicates that the main body can return the response value with return, and compiler will not automatically recognize the type. If no numeric columns need such a forward (void ).
View a column
^ (Int A) {return a * ;};
This indicates that the block will return the Square Value of the incoming value (int A is the number column, return a * A; is the row as the main body ). Add ";" because it is a descriptive statement, and the last {} should also be added ";" because the block is an object entity.
Usage is
Int result = ^ (int A) {return a * A;} (5 );
It's weird. In the lower case, the 5 values in the lower case will be converted into the value of A, and then the block outputs 5*5 = 25 to the result.
Is there a way to keep it simple? Otherwise it will take so long every time? Yes. Next we will introduceBlock pointerThe things of Alibaba Cloud refer to our legal methods.
Block pointerYes.
Return Value (^ name) (numeric column );
Let's look at a column.
INT (^
Square) (INT );
// One is calledSquareOfBlock pointerWhich points to the block that has an int incoming and INT outgoing
Square = ^ (int A) {return a * A;}; // specify the actual block of Square
Example of using block pointer
Int result = square (5); // isn't it actually a funtion?
You can also regard block pointer As a vertex number to give a function, for example
Void myfuction (INT (^ mysquare) (INT); // function declaration,
Returns the block type data with an int value and an int value.
This is the call when calling this myfunction.
INT (^ mysqaure) (INT) = ^ (int A) {return a * ;};
// First, give a solid block pointer named mysquare.
Myfunction (mysqaure); // give the block pointer mysquare to the Function
Or you don't need to block pointer to directly give a block entity.
Myfunction (
^ (Int A) {return a *});
When it is the objective-C method's internal input value, it is necessary to add a small value to the variable before the change, because some should be like this.
-(Void) objcmethod :(
INT (^) (INT)) Square; // The type of the square variable is int (^) (INT)
Does Yan have a basic understanding of block? Next, we will introduce the behavior and features related to block.
First, let's take a look at how to access external changes in the block.
Access changes
1. You can retrieve the changes of the same scope as block pointer:
{
Int outa = 8;
INT (^ myptr) (INT) = ^ (int A) {return outa + ;};
// You can set the outa value of the same scope in the block.
Int result = myptr (3); // result is 11
}
Let's look at another interesting example.
{
Int outa = 8;
INT (^ myptr) (INT) = ^ (int A) {return outa + ;};
// You can set the outa value of the same scope in the block.
Outa = 5;// Change the value of outa before calling myptr
Int result = myptr (3); // The value of result is11Not8
}
In fact, when myptr uses outa in its main body, it performs a copy operation to copy the value of outa. Therefore, even if outa adds a new value, it does not affect the copy value in myptr.
It should be noted that this refers to the value of change. If the value of this change is the position of a memory, this variable is a pointer. It indicates that the value can be changed in the block.
{
Nsmutablearray * mutablearray = [nsmutablearray arraywithobjects: @ "one", @ "two", @ "three", nil];
Int result = ^ (int A) {[mutablearray removelastobject]; return a * A;} (5 );
Nslog (@ "test array % @", mutablearray );
}
The original mutablearray value is {@ "one", @ "two", @ "three"} after the object pointed to by mutablearray is changed in the block, the value of mutablearray is {@ "one", @ "two "}
2. directly access static changes
{
Static int outa = 8;
INT (^ myptr) (INT) = ^ (int A) {return outa + ;};
// You can set the outa value of the same scope in the block.
Outa = 5;// Change the value of outa before calling myptr
Int result = myptr (3); // The value of result is
8Because outa is a static variable, it will directly respond to its value.
}
You can even directly change the outa value in the block, such
{
Static int outa = 8;
INT (^ myptr) (INT) = ^ (int A) {outa = 5; return outa + ;};
// Change the outa value in the block.
Int result = myptr (3); // The value of result is
8Because outa is a static variable, it will directly respond to its value.
}
3. Block Variable
If a variable is prefixed with the _ block character (note that there are two bottom blocks before the block), the variable is block variable. You can modify the variable value in the block as needed.
{
_ Block int num = 5;
INT (^ myptr) (INT) = ^ (int A) {return num ++ ;};
INT (^ myptr2) (INT) = ^ (int A) {return num ++ ;};
Int result = myptr (0 );
Result = myptr2 (0 );
}
Because both myptr and myptr2 use the num block variable, the final result value is 7.
Lifecycle and Memory Management
Because block is also self-built from nsobject, it is very important to manage its lifecycle and memory.
A block is first put into a stack. In other words, when its lifecycle ends with a method or function, it will be recycled, just like the lifecycle of a general change.
For the management of the memory, please follow these requirements
1. The block pointer entity will be cleared after the method or function end.
2. If you want to save the block pointer's actual body to use the-Copy command, the block pointer will be placed in heap.
2.1 The Block Variable used in the block main will also be moved to the heap and there will be a new location for the record, and the block updated to use this block variable will be directed to the new location.
2.2 normal variable values will be copied
2.3 If the variable used in the main body is an object, the object will be retain, and the block release will also be release.
The objects used in the 2.4 _ Block Variable cannot be retaken.
First, let's take a look at this example.
Typedef int (^ myblock) (INT );
Myblock genblock ();
Int main (){
MyblockOutblock= Genblock ();
Int result = outblock (5 );
Nslog (@ "result is % d", [outblock retaincount]); // segmentation fault
Nslog (@ "result is % d", result );
Return 0;
}
Myblock genblock (){
Int A = 3;
MyblockInblock= ^ (Int n ){
Return N *;
};
ReturnInblock;
}
This program is assigned to the main function by the block generated in genblock.OutblockChange the number, the program will get
Segmentation fault
(Metadata: When a in genblock is removed, the result can be obtained. This is because the system caches the memory, and inblock does not always exist, after a long time, it will still be recycled. Do not think it is the correct method)
It indicates that we have used a memory that is not used. In this example, the memory is in genblock.InblockChanges are recycled at return,OutblockThere cannot be a valid location-retaincount.
If the value of inblock needs to be retained at this time, use the-Copy command to change genblock
Myblock genblock (){
Int A = 3;
Myblock inblock = ^ (int n ){
Return N *;
};
Return [inblock copy];
}
In this way, the return value of [inblock copy] will be placed in heap and can be used all the time (remember to release)
The response result is
Result is 1
Result is 15
Remind you to remember the release outblock again.
If the value of [inblock copy] is retained
Myblock genblock (){
Int A = 3;
Myblock inblock = ^ (int n ){
Return N *;
};
Return [[inblock copy] autorelease];
}
-The Copy command aims to move the block from the stack to heap. autorelease adds the flat retaincount to autorelogoop. After the rollback, the block will be cleared after the event ends.
Next, the local variable accessed by the block is the object type, and then the Copy command is executed.
Myblock genblock (){
Int A = 3;
Nsmutablestring * mystring = [nsmutablestring string];
Myblock inblock = ^ (int n ){
Nslog (@ "retain count of string % d", [mystring retaincount]);
Return N *;
};
Return [inblock copy];
}
The result is printed.
Retain count of string 2
This result is similar to the one mentioned above in 2.3. The local variable is retaken.
Then merge into 2.4, and add _ block to the front of local variable.
Myblock genblock (){
Int A = 3;
_ Block nsmutablestring * mystring = [nsmutablestring string];
Myblock inblock = ^ (int n ){
Nslog (@ "retain count of string % d", [mystring retaincount]);
Return N *;
};
Return [inblock copy];
}
The result of the response line is
Retain count of string 1
Block copying considerations
If the copying block action is performed in the class method
1. If there is direct access to self in the block, self will be retain
2. If the instance variable (directly or from accessor) is stored in the block, self will be retain
3. When the object stored in the local variable is retrieved, the object will be retain
Let us look at a self-built class
@ Interface myobject: nsobject {
Nsstring * title;
Void (^ mylog) (nsstring * Deco );
}
-(Void) LOGNAME;
@ End
@ Implementation myobject
-(ID) initwithtitle :( nsstring *) newtitle {
If (Self = [Super init]) {
Title = newtitle;
Mylog = [^ (nsstring * Deco) {nslog (@ "% @", Deco, title, Deco);} copy];
}
Return self;
}
-(Void) LOGNAME {
Mylog (@ "= ");
}
-(Void) dealloc {
[Mylog release];
[Title release];
[Super dealloc];
}
@ End
Use the following in main:
Myobject * mobj = [[myobject alloc] initwithtitle: @ "car"];
Nslog (@ "retaincount of myobject is % d", [mobj retaincount]);
[Mobj LOGNAME];
The result of the preceding row is
Retaincount of myobject is 2
= Car =
This is because the 'mylog' block pointer uses the 'title' instance variable' in the myobject structure, and then the retain self is the object of myobject.
The amount of memory should not be the same, which will cause retain cycle. The improvement method is to change the constructor to this.
-(ID) initwithtitle :( nsstring *) newtitle {
If (Self = [Super init]) {
Title = newtitle;
Mylog = [^ (nsstring * Deco) {nslog (@ "% @", Deco, newtitle, Deco);} copy];
}
Return self;
}
Use newtitle in the block owner instead of the title. In this way, self will not be retaken.
The last small trap
Void (^ mylog) (void );
Bool result;
If (result)
Mylog = ^ {nslog (@ "yes ");};
Else
Mylog = ^ {nslog (@ "no ");};
Mylog ();
This will probably take effect because the mylog is cleared after the if or else end. Remember.
Use copy to solve this problem, but remember release.