ArticleDirectory
Block can help us organize independentCodeAnd improve reusability and readability. Ios4 introduces this feature in uikit. Blocks are used for more than 100 Apple APIs, so this is a must-start knowledge.
What is block?
You can use^To declare a block variable, which indicates the beginning of a block.
- IntNum1 = 7;
- Int(^ Ablock )(Int) = ^)IntNum2 ){
- ReturnNum1 + nunm2;
- };
In the above Code, we declare a block as a variable, so we can use it as a function:
- Nslog (@"% D", Ablock (49); // adds 49To7 which gives us 56.
We have just looked at block as a variable, but we usually use block in an internal connection mode, for example, in a variable. The API either uses a block to perform an operation on an object set or uses it as the callback after an operation is completed.
- Nscomperator comparestringsblock = ^ (ID stringa, Id stringb ){
- Nsange ranges = nsmakerange (0, [stringa length]);
- Return(Stringa compare: stringb options: comparisonoptions range: ranges locale: currentlocale];
- };
-
- Nsarray * comparesortarray = [arrayofstringdays sortarrayusingcomparator: comparestringsblock]);
Block has the advantage of creating a temporary function as an expression. The Apple document states:
Block is an anonymous Inline code set that meets the following requirements:
- A parameter list of the specified type is the same as a function.
- There is a type of return value that can be deduced or declared
- It can capture the State from its defined meaning range.
- You can change the state of the word meaning range as needed.
- It can share the possibility of changes with other blocks defined in the same word scope.
- You can continue to share and modify the state of the Meaning range (stack frame) after the meaning range (stack frame) is destroyed.
A block is a self-contained small code segment that encapsulates the task units used for Traversing (linear traversal) or callback and can be executed concurrently.
Declare and use block
The Apple document describes how to declare a block as a variable and use it as a function:
-
- INT (^ onefrom) (INT) = ^ (INT anint ){
-
- Return anint-1;
-
- };
-
- // We have created an inline block ^ (INT anint)... and its function body and result are passed to another block named onefrom.
-
-
-
- Printf ("1 from 10 is % d", onefrom (10 ));
- // Print out: "1 from 10 is 9"
-
- // This block function (distancetraveled) passes in three float parameters and returns the float value.
-
-
-
- Float (^ distancetraveled) (float, float, float) =
-
-
-
- ^ (Float startingspeed, float acceleration, float time ){
-
- FloatDistance= (Startingspeed * Time) + (0.5 * acceleration * time );
- Return distance;
-
- };
You can also pass in a block as a parameter, instead of declaring them in the above way, so that you can easily implement the block as a parameter by associating the code in the same way.
- Nsarray * anarray = [nsarray arraywithobjects :@"Cat",@"Dog", Nil];
- Sortfunction (anarray, ^ (string * a string * B ){
- If (A == @"Cat")Return True;});
In this way, we can see that an inline block code segment occupies the position of the last parameter (which must be the last parameter in the parameter list. Cocoa provides a lot of block-based methods, so that you can pass in the block as a method parameter:
- Nsarray * array = [nsarray arraywithobjects :@"",@"B",@"C", Nil];
-
- Nsset * filterset = [nsset setwithobjects :@"",@"Z",@"Q", Nil];
-
-
-
- Bool (^ test) (id obj, nsuinteger idx, bool * Stop); // block DeclarationReturnsBool, Params Inc. IDAndBool
- // BodyOfBlock gets the block literal ^ (id obj, nsuinteger idx, bool * Stop )...AndThe body Logic
-
- Test = ^ (id obj, nsuinteger idx, bool * Stop ){
-
- If (idx & lt; 5 ){
-
- If ([filterset containsobject: OBJ]) {
-
- ReturnYes;
-
- }
- }
-
- Return No;
-
-
-
- };
Another example provided by Apple is:
-
- _ Block bool found =No;
-
- Nsset * aset = [nsset setwithobjects :@"Alpha",@"Beta",@"Gamma",@"X", Nil];
-
- Nsstring * string = @"Gamma";
- // We provide below a wayOfHowToEnumerate, using our own compare Logic
-
- [Aset enumerateobjectsusingblock: ^ (id obj, bool * Stop ){
-
- If ([OBJ localizedcaseinsensitivecompare: String] = nsorderedsame ){
-
- * Stop = yes;
-
- Found = yes;
-
- }
-
- }];
As you can see, it takes a little while to have it sink in but once
You get it, it's quite simple. I suggest looking at Apple's
Documentation, as well as looking at the referenced APIs to see how they
Are used. Practice makes perfect.
Source: http://answers.oreilly.com/topic/2281-how-to-use-blocks-with-ios/
Objective-C Block
Block
Apple uses the extension Statement C, objective-C, C ++, and block. Currently, only Mac 10.6 and IoS are supported.
4. Support. A block is composed of a bunch of executable programs. You can also perform a function without a name (anonymous function ). For Mac
Platforms before 10.6 or IOS 4.0 can utilize http://code.google.com/p/plblocks/
This project supports the block encryption method.
Apple has
Dispach), which is used in the concurrency environment for better efficiency. The block generator method generates a mechanism from GCD, which is encapsulated with blocks.
A workload is handed over to GCD, and GCD has a macro field that can be used to allocate the best decisions for CPU, GPU, and 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
^ (IngressNumeric Column){Act as the Main Body};
The block is started with "^" and then wrapped by a small volume.Numeric Column(For example, int A, int B, float C ),Behavior mainBlock literal is a famous term for its inclusion in big data.Act as the Main BodyReturn can be used to return the response value. compiler will not automatically recognize the response value. If no numeric columns need such a forward (void ).
View a column
^ (Int){Return a *;};
This indicates that the block will return the Square Value of the input value (IntYesNumeric Column,Return a *;YesAct 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 *;} (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 is8Because 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 is8Because outa is a static variable, it will directly respond to its value.
}
3. Block Variable
Add a modifier before a change.__Block (note that there are two bottom blocks before the block), and the change 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. Use-CopyCommand, so 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 () {
myblock outblock = genblock ();
int result = outblock (5);
nslog (@ "result is % d", [outblock retaincount]); // segmentation fault
nslog (@ "result is % d", result );
return 0;
}< br> myblock genblock () {
int A = 3;
myblock inblock = ^ (int n) {
return N * A;
};
return inblock ;
}
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 [inblockCopy];
}
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 [[inblockCopy]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;
_ BlockNsmutablestring * 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
@ InterfaceMyobject: nsobject {
Nsstring * title;
Void (^Mylog) (Nsstring * Deco );
}
-(Void) LOGNAME;
@ End
@ ImplementationMyobject
-(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.
From: http://www.cnblogs.com/pengyingh/articles/2343087.html