#iOS#HeminWoniOS开发

iOS中block的使用详解

2016-07-25  本文已影响1371人  eightzg

block的声明和简单使用

block的定义方式
void(^block1)() = ^{
    NSLog(@"调用了block1");
};
void(^block2)(int) = ^(int a){
       NSLog(@"调用了block2");     
};
int(^block3)() = ^int{
    return 3;
};

block定义总结

总结:block的定义,不管block有没有返回值,block的实现部分都可以省略;若block有参数,则参数类型和传入参数的值不能省略。

Paste_Image.png

block使用场景之----代理传值

在开发中控制器逆传传值最常用的就是用代理的方法,然而用block也可以实现逆传传值,而且更加简单方便。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    ModalViewController *modalVc = [[ModalViewController alloc] init];
    modalVc.view.backgroundColor = [UIColor brownColor];
    modalVc.block = ^(NSString *value) {
      
        NSLog(@"%@",value);
    };
    
    // 跳转
    [self presentViewController:modalVc animated:YES completion:nil];
}
@property (nonatomic, strong) void(^block)(NSString *value);
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (_block) {
        _block(@"我是萌萌哒ModalViewController");
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}
Paste_Image.png
block的内存管理

MRC

Paste_Image.png
- (void)viewDidLoad {
    [super viewDidLoad];
    //局部变量a
    int a = 3;
    void(^block)() = ^{
        NSLog(@"调用block %d",a);
    };
    NSLog(@"%@",block);
}
Paste_Image.png
//全局变量a
int a = 3;

- (void)viewDidLoad {
    [super viewDidLoad];
    void(^block)() = ^{
        NSLog(@"调用block %d",a);
    };
    NSLog(@"%@",block);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //静态变量a
    static int a = 3;
    void(^block)() = ^{
        NSLog(@"调用block %d",a);
    };
    NSLog(@"%@",block);
}
Paste_Image.png
//定义copy修饰的block属性
@property (nonatomic, copy) void(^block)();
- (void)viewDidLoad {
    [super viewDidLoad];
    int a = 3;
    void(^block)() = ^{
        NSLog(@"调用block%d",a);
    };
    self.block = block;
    NSLog(@"%@",self.block);
}
Paste_Image.png Paste_Image.png
总结
只要block没有引用外部局部变量,block放在全局区
只要Block引用外部局部变量,block放在栈区.
block只能使用copy,不能使用retain,使用retain,block还是在栈区

ARC

block的内存管理总结
 总结:block里面引用全局变量或者静态变量,放在全局区__NSGlobalBlock__
 
 *  MRC情况:
 *  block里面引用局部变量,存放在栈区__NSStackBlock__
 *  MRC中修饰block只能用copy,不能用retain,因为retain修饰block还在栈中,若block是局部变量,不能包住block的命,再次访问会造成坏内存访问。
 
 *  ARC情况:
 *  block里面引用局部变量,存放在堆区__NSMallocBlock__
 *  block在ARC情况下用strong修饰
 *  对于NSString和block在ARC尽量用strong,因为copy底层的setter方法会对新对象做一次copy操作,还要判断是不是不可变对象,浪费性能
 */
block的循环引用

在ViewController中以modal的方式展示ModalViewController,在ModalViewController中调用dismiss方法销毁控制器。则在dealloc方法中会打印ModalViewController被销毁。

然而若定义一个block属性,并在block的实现中做如下操作:

@property (nonatomic, strong) void(^block)();
_block = ^{
    NSLog(@"%@",self);
};

此时当调用ModalViewController的dismiss方法的时候不会调用dealloc方法中的打印语句,说明ModalViewController没有被真正的销毁。因为ModalViewController强引用一个block属性,block会对内部的强指针self进行一次强引用。所以造成循环引用

__weak typeof(self) weakSelf = self;
_block = ^{
    NSLog(@"%@",weakSelf);   
};

block的变量传递

/***************  1  **************/
- (void)viewDidLoad {
    [super viewDidLoad];    
    //普通局部变量a
    int a = 3;
    void(^block)() = ^{
        NSLog(@"%d",a);  
    };
    a = 5;
    block();
}

如果这样呢?

/***************  2  **************/
- (void)viewDidLoad {
    [super viewDidLoad];    
    //静态变量a
    static int a = 3;
    void(^block)() = ^{
        NSLog(@"%d",a);  
    };
    a = 5;
    block();
}

这样呢?

/***************  3  **************/
//全局变量a
int a = 3;
- (void)viewDidLoad {
    [super viewDidLoad];    
    void(^block)() = ^{
        NSLog(@"%d",a);  
    };
    a = 5;
    block();
}

这样呢?

/***************  4  **************/
- (void)viewDidLoad {
    [super viewDidLoad];    
    //用__block修饰的局部变量a
    __block int a = 3;
    void(^block)() = ^{
        NSLog(@"%d",a);  
    };
    a = 5;
    block();
}

实际编译可以得出结果,除了1的打印结果是3,剩下的都是5。那么可以总结出结论如下:

* 如果block中是普通的局部变量,是值传递,即在局部变量声明的那一刻就把局部变量的值放到block中了,之后在修改不会造成影响
* 如果是静态变量,全局变量,__block修饰的变量,block都是指针传递。指针传递的值可以修改。
上一篇下一篇

猜你喜欢

热点阅读