Directory
-
- Basic use of Block
-
- Block’s statement
- Implementation of Block
- Block call
- Block is used as a formal parameter
- Block is used as an attribute
-
- Give the Block an alias
- Block copy
- Block capture mechanism
-
- local variables of type auto
- Brief analysis of __block
- static type local variables
- global variables
- other problems
Basic use of Block
What is Block?
Block (block), OC object that encapsulates function calls and calling environment, Objective-C closure (can access external values internally), equivalent to function pointer in C language, writes a function Inside a function, and OC does not have the syntax for nesting functions (methods)
Block’s statement
void(^blockName)(); int(^blockName2)(int a, int b, int c);
Format: Return value (^block name) (parameter list)
^
The symbol representing the block
Implementation of Block
- No parameters, no return value
void(^blockName)(void) = ^{<!-- --> };
- There are parameters and no return value
void(^blockName)(int a, int b) = ^(int a, int b){<!-- --> };
- No parameters, return value
int(^blockName)(void) = ^int{<!-- --> return 3; };
The return value of the implementation part can be omitted, like this:
int(^blockName)(void) = ^{<!-- --> return 3; };
- There are parameters and return values
int(^blockName)(int a, int b) = ^int(int a, int b){<!-- --> return 3 + a * b; };
The return value int
of the implementation part can also be omitted
Block call
//No parameters and no return value blockName(); //There are parameters and return values int result = blockName(7, 12);
Now that the declared blockName
represents a block, you can call this block either through blockName(7, 12);
, or like this:
int result = ^(int a, int b) {<!-- --> return 3 + a + b; }(7, 12);
Block is used as a formal parameter
The declaration of Block as a formal parameter in the method is slightly different from the above format (the name of the block is outside)
Now the following methods are implemented in the Jaxon
class and the Jacky
class respectively:
Jaxon.h
- (void)askJackyForHelp: (void(^)(int num))blockName isOK: (void(^)(BOOL boolValue))completion;
Jaxon.m
- (void)askJackyForHelp:(void (^)(int))blockName isOK:(void (^)(BOOL))completion {<!-- --> blockName(3); //The parameters passed into the completion block are either 1 or 0 completion(arc4random() % 2); }
Jacky.m
- (void)helpDoWith: (int)num {<!-- --> NSLog(@"Help %d times", num); }
Next call in the main
function:
Jaxon* jaxon = [[Jaxon alloc] init]; [jaxon askJackyForHelp:^(int num) {<!-- --> Jacky* jacky = [[Jacky alloc] init]; [jacky helpDoWith: num]; } isOK:^(BOOL boolValue) {<!-- --> //The probability of success and failure are each half if (boolValue) {<!-- --> NSLog(@"Help successful"); } else {<!-- --> NSLog(@"Help failed"); } }];
operation result:
Can this function as a proxy? Jaxon
entrusts Jacky
to help with tasks. Jacky is entrusted with things that Jaxon cannot implement. Therefore, the Block block can also be used for interface transmission. value or other programming that requires the use of proxy mode
Block is used as an attribute
Give the Block an alias
It was also mentioned at the beginning of the article that a block is actually an object and can be understood as a data type.
Then you can also use the typedef
keyword to alias the Block. See the following example:
typedef void(^Help)(int num); typedef void(^Finish)(BOOL boolValue);
The above method can also be declared like this:
- (void)askJackyForHelp:(Help)blockName isOK:(Finish)completion;
The attribute keyword of the block generally needs to be copy
:
@interface Jaxon : NSObject //no alias @property (nonatomic, copy)void(^helpBlock)(int num); //has alias //@property (nonatomic, copy)Help helpBlock; - (void)askMyselfDo; @end @implementation Jaxon - (void)askMyselfDo {<!-- --> self.helpBlock(5); } @end
main function:
Jaxon* jaxon = [[Jaxon alloc] init]; jaxon.helpBlock = ^(int num) {<!-- --> NSLog(@"I did it myself %@ times", @(num)); }; [jaxon askMyselfDo];
operation result:
Block copy
Regarding the copy
keyword, the editor also briefly understands it, and will analyze the underlying principles in detail later:
In the
ARC
environment, the compiler will automatically copy the block on the stack to the heapaccording to the situation, such as the following situations: : When manually calling the
copy` method of block;
- When block is used as a function return value (used a lot in the Masonry framework);
- When assigning block to the
__strong
pointer;- When block is used as a method parameter in the Cocoa API whose method name contains
usingBlock
;- block as a method parameter of GCD API.
How to write block as an attribute:
Writingstrong
orcopy
underARC
will make a strong reference to the block and automatically copy the block from the stack to the heap;
It is recommended to writecopy
so that it is consistent under MRC and ARC.
Block is stored in the stack area when it is first created, and copy
to the heap area when used.
Block capture mechanism
In order to ensure that Block can access external variables normally, Block has a variable capture mechanism.
Local variables of auto type
auto
Variables: Normally defined variables are of auto type by default, but are omitted.
auto int age = 20;
Local variables of auto type will be captured
inside the block block, and the access method is value transfer
int age = 10; NSLog(@"%d %p", age, & amp;age); void(^blockName)(void) = ^ {<!-- --> NSLog(@"%d %p", age, & amp;age); }; age = 20; //It can be printed out, indicating that the block block can access external information. blockName(); NSLog(@"%d %p", age, & amp;age);
According to the running results, the following two points can be drawn:
- When a local variable of type
auto
is captured inside a block, an identical member variable will be automatically generated inside the block to store the value of this variable, so the printed Theage
address outside the block is different from the internalage
address. - Due to
value transfer
, modifying the value of the externalage
variable will not affect the variables inside the block.
A brief analysis of __block
External variables can only becalled inside the Block and cannot be modified:
By default, Block uses a read-only copy of captured external variables, so the value of external variables cannot be directly modified inside Block.
The solution is as follows:
- The variable is modified with
static
(reason: capturing a local variable of static type ispointer passing
, and the memory address of the variable can be accessed) - global variables
__block
(We only want to use this variable temporarily and change it temporarily, but if we change it to static variables and global variables, they will always be in memory)
When a variable is modified by __block
, block can modify external global variables:
__block int age = 10; NSLog(@"%d %p", age, & amp;age); void(^blockName)(void) = ^ {<!-- --> age = 30; NSLog(@"%d %p", age, & amp;age); }; blockName(); NSLog(@"%d %p", age, & amp;age);
Local variables of static type
Local variables of static
type will be captured
inside the block, and the access method is pointer passing
static int age = 10; NSLog(@"%d %p", age, & amp;age); void(^blockName)(void) = ^ {<!-- --> NSLog(@"%d %p", age, & amp;age); }; age = 20; blockName(); NSLog(@"%d %p", age, & amp;age);
- When a local variable of type
static
is captured inside a block, a pointer of the same type will be generated inside the block , pointing to the address of theage
variable captured inside. - Due to
pointer passing
, modifying the value of the externalage
variable will affect theage
variable inside theblock
Global variables
Global variables will not be captured
inside the block, and the access method is direct access
int _age = 10; static int _height = 175; int main(int argc, const char * argv[]) {<!-- --> @autoreleasepool {<!-- --> NSLog(@"%d %p", _age, & amp;_age); void(^blockName)(void) = ^ {<!-- --> _age = 30; NSLog(@"%d %p", _age, & amp;_age); }; blockName(); _age = 20; NSLog(@"%d %p", _age, & amp;_age); } return 0; }
Other questions
For local variables of object
type, block will capture them together with their ownership modifier
Why do local variables need to be captured but global variables do not?
- Because of the scope, global variables can be directly accessed anywhere, so there is no need to capture them;
- Local variables cannot be directly accessed from the outside, so they need to be captured;
- Local variables of auto type may be destroyed, and their memory will disappear. It is impossible for the block to access that memory when executing code in the future, so its value is captured;
- Static variables will always be stored in memory, so just capture their address.