Definition and use of block in iOS

 

concept

The code block block is an extension to the C language introduced by Apple in iOS4 to implement the characteristics of anonymous functions. Block is a special data type that can define variables normally, as parameters, and as return values. In particular, block You can also save a piece of code and call it when needed. At present, block has been widely used in iOS development, often used for GCD, animation, sorting and various callbacks.

block: We call it a code block, which is similar to a method. And each method goes from the hard disk to the memory when it is called, and then executes it, and then disappears after the execution. Therefore, the memory of the method does not need to be managed by us, that is, the method is in the stack area of ​​the memory. Therefore, the block is not like the class object in OC (in the heap area), it is also in the stack area. If we use block as an attribute of an object, we will use the keyword copy to modify it, because it is in the stack area and we cannot control its demise. When we modify it with copy, the system will copy the implementation of the block. Share it to the heap area, so that our corresponding attribute will have the ownership of the block. It can be guaranteed that the block code block will not die prematurely.

Definition and use

Declaration of block variable

The declaration format of the block variable: return value type (^block name) (parameter list);

1

2

3

4

5

block 变量的声明格式:返回值类型(^block名字)(参数列表);

 //声明一个无返回值,两个参数的 block

 void(^block1)(NSString *a,NSString *b);

 //省略写法

 void(^block2)(NSString *,NSString *);

Assignment of block variables

1

2

3

4

5

6

//block变量的赋值

//block变量名 = ^(参数列表){函数体};

block1 = ^(NSString *x,NSString *y){

NSLog(@"%@--%@",x,y);

};

block1(@"123123",@"QWEQWEQWE");

Assign value while declaring block variable

1

2

3

4

5

//声明 block 变量的同时进行赋值

int(^block3)(int) = ^(int a){

return a*3;

};

NSLog(@"%d",block3(3));

Use typedef to define the block type

In the actual use of Block, we may need to repeatedly declare multiple Block variables with the same return value and the same parameter list. It will be very cumbersome to write a long series of codes repeatedly to declare variables, so we can use typedef to define Block type

1

2

3

4

5

6

7

#pragma mark 使用 typedef 定义 block 类型

 //定义一个无返回值类型 无参数列表的 block

 typedef void (^Block4)();

 Block4 block4 = ^(){

  NSLog(@"i am block4");

 };

 block4();

block as a function parameter

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#pragma mark block作为函数参数

 int(^block5)(int,int) = ^(int a,int b){

  return a+b;

 };

 [self useBlock5:block5];

  

 //简化书写

 //typedef int (^Block6)(int,int);(全局声明)

 Block6 block6 = ^(int a,int b){

  return a+b;

 };

 [self useBlock6:block6];

  

  

- (void)useBlock5:(int(^)(int,int))block5 {

 NSLog(@"block5:%d",block5(3,5));

}

- (void)useBlock6:(Block6 )block6{

 NSLog(@"block6:%d",block6(4,5));

}

Access local variables in the block

  • Local variables can be accessed in the block
  • Modify the local variables after the Block is declared and before the Block is called. When the Block is called, the value of the local variable is the old value before the modification.
  • Local variables cannot be modified directly in the block

1

2

3

4

5

6

7

8

#pragma mark block -----------访问局部变量

 //block 中不可以直接修改局部变量

 int value1 = 100;

 void (^block7)(void) = ^(){

   NSLog(@"value1:%d",value1);

 };

 value1 = 200;

 block7();//输出100

  • Use the underscore and underscore block modification before the local variables, modify the local variables after the block is declared and before the block is called. When the block is called, the value of the local variable is the new value after the modification.
  • Use the underscore underline block modification before the local variables, and the local variables can be directly modified in the block

1

2

3

4

5

6

7

8

9

10

#pragma mark block -----------访问局部变量

 //block 中不可以直接修改局部变量

 //在局部变量前使用__block修饰,在Block中可以直接修改局部变量

 __block int value1 = 100;

 void (^block7)(void) = ^(){

   value1++;

  NSLog(@"value1:%d",value1);

 };

 value1 = 200;

 block7();//输出100 __block 修饰之后输出200

Access global variables in the block

Modify the global variables after the block is declared and before the block is called. When the block is called, the value of the global variable is the new value after the modification.

1

2

3

4

5

6

7

8

9

10

#pragma mark ------------------block 访问全局变量

 //在Block中可以访问全局变量

 value2 = 100;

 void(^block8)(void) = ^(){

  //在Block中可以直接修改全局变量

  self->value2++;

  NSLog(@"value2:%d",self->value2);

 };

 value2 = 200;

 block8();

Access static variables in the block

1

2

3

4

5

6

7

8

9

#pragma mark --------block内访问静态变量

 static int value3 = 100;

 void(^block9)(void) = ^(){

  value3++;//在Block中可以直接修改静态变量

  NSLog(@"value3:%d",value3);

 };

 //在声明Block之后、调用Block之前对静态变量进行修改,在调用Block时静态变量值是修改之后的新值

 value3 = 200;

 block9();

Circular reference problem caused by block

If there is a Block property inside the object, and the object is accessed inside the Block, it will cause a circular reference

Situation One

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

@interface Person : NSObject

 

@property (nonatomic, copy) void(^myBlock)();

 

@end

 

 

@implementation Person

 

- (void)dealloc

{

 NSLog(@"Person dealloc");

}

 

@end

 

 

Person *p = [[Person alloc] init];

   

p.myBlock = ^{

 NSLog(@"------%@", p);

};

p.myBlock();

   

// 因为myBlock作为Person的属性,采用copy修饰符修饰(这样才能保证Block在堆里面,以免Block在栈中被系统释放),所以Block会对Person对象进行一次强引用,导致循环引用无法释放

Situation two

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@interface Person : NSObject

 

@property (nonatomic, copy) void(^myBlock)();

 

- (void)resetBlock;

 

@end

 

 

@implementation Person

 

- (void)resetBlock

{

 self.myBlock = ^{

  NSLog(@"------%@", self);

 };

}

 

- (void)dealloc

{

 NSLog(@"Person dealloc");

}

 

@end

 

 

Person *p = [[Person alloc] init];

[p resetBlock];

 

// Person对象在这里无法正常释放,在resetBlock方法实现中,Block内部对self进行了一次强引用,导致循环引用无法释放

The way to solve the circular reference is to use a weak reference pointer to point to the object, and then use the weak reference pointer inside the block to operate, which avoids the block from making strong references to the object

Situation One

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

@interface Person : NSObject

 

@property (nonatomic, copy) void(^myBlock)();

 

@end

 

 

@implementation Person

 

- (void)dealloc

{

 NSLog(@"Person dealloc");

}

 

@end

 

 

Person *p = [[Person alloc] init];

__weak typeof(p) weakP = p;

 

p.myBlock = ^{

 NSLog(@"------%@", weakP);

};

p.myBlock();

   

// Person对象在这里可以正常被释放

Situation two

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

@interface Person : NSObject

 

@property (nonatomic, copy) void(^myBlock)();

 

- (void)resetBlock;

 

@end

 

 

@implementation Person

 

- (void)resetBlock

{

 // 这里为了通用一点,可以使用__weak typeof(self) weakP = self;

 __weak Person *weakP = self;

 self.myBlock = ^{

  NSLog(@"------%@", weakP);

 };

}

 

- (void)dealloc

{

 NSLog(@"Person dealloc");

}

 

@end

 

 

Person *p = [[Person alloc] init];

[p resetBlock];

 

// Person对象在这里可以正常被释放

Guess you like

Origin blog.csdn.net/wu347771769/article/details/115003154