iOS block

54 阅读2分钟

block的分类

  • 全局__NSGlobalBlock__
        // <__NSGlobalBlock__: 0x100128240>
        // 没有使用外部变量
        NSLog(@"%@",  ^(){
            NSLog(@"hello world");
        });
        
        // 使用静态变量
        static int age = 100;
        NSLog(@"%@",  ^(){
            NSLog(@"age is %d", age);
        });
        
        // 使用全局变量 写在函数外面
        //        int pai = 31.4;
        //        - (void)viewDidLoad {
        
        NSLog(@"%@",  ^(){
            NSLog(@"pai is %d", pai);
        });

        //__NSMallocBlock__
        int a = 10;
        void (^ m) (void) = ^ (void){
            NSLog(@"a is %d",a );
        };
        NSLog(@"%@", m);

        //__NSStackBlock__
        int a = 10;
        void (^ __weak hello) (void) = ^ (void){
            NSLog(@"a is %d",a );
        };
        NSLog(@"%@", hello);


copy

因为默认的block是栈内存的,当前函数结束就会被销毁。所以我们需要使用copy。属性使用strong也会调用copy。

引用计数

弱引用的block也会捕获外部变量,同时强引用也会再次捕获。因此强引用加2。

// 结果为3和4
        NSObject *obj = [NSObject new];
        
        void (^block1)(void) = ^(){
            NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
        };
        block1();
        
        
        void (^__weak block2)(void) = ^(){
            NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
        };
        block2();

        NSObject *obj = [NSObject new];
        void (^block0)(void);
        {
            void (^block1)(void) = ^(){
                NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
            };
            // 由于block1为堆,所以这里不会再次捕获
            block0 = block1;
            block1();//3
            
        }
        //2 此时,没有栈的block
        block0();
        
        void (^__weak block2)(void) = ^(){
            NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
        };
        // 3 此时又多了一个栈捕获
        block2();

循环引用

    // 循环引用
    // 1 weakSelf不会对self强引用
    __weak typeof(self) weakSelf = self;
    // 2 weakSelf此时不为nil,因此本质还是让当前对象的block强引用当前对象
    weakSelf.block = ^ (){
        self.name = @"hello";
    };

下面代码中self引用了block。而Block又引用了self,因此会导致循环引用。

@interface SecondViewController ()
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) void (^block)(void);
@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor redColor];
    self.block = ^ (){
        self.name = @"test";
    };
    
}

改成下面的方式,效果一样,本质还是引用了self.

    self.block = ^ (){
        _name = @"demo";
    };

使用__weak解决循环引用。

    __weak typeof(self) weakSelf = self;
    self.name = @"test";
    self.block = ^ (){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",weakSelf.name);
        });
    };
    self.block();

但是上面的代码会导致weakself为空,所以打印的是null。此时需要再次进行强引用。下面在页面退出的时候。会先等block执行结束再dealloc。

    self.view.backgroundColor = [UIColor redColor];
    __weak typeof(self) weakSelf = self;
    self.name = @"test";
    self.block = ^ (){
        __strong typeof(self) strongSelf = weakSelf;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",strongSelf.name);
        });
    };
    self.block();

通过临时变量解决循环引用

这个方法有限制,只能使用一次。

    self.name = @"test";
    __block
    SecondViewController *vc = self;
    self.block = ^ (){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",vc.name);
            vc = nil;
        });
    };
    self.block();

参数传递解决循环引用

因为block没有引用外部变量。

    self.name = @"test";
    self.block = ^ (SecondViewController *vc){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",vc.name);
        });
    };
    self.block(self);

static和循环引用

static是全局作用域,赋值的时候会强引用。对弱引用的强引用会导致强引用。

static SecondViewController *a;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor redColor];
    self.name = @"test";
    
    __weak typeof(self) weakSelf = self;
    a = weakSelf;
}