block

2018-03-15  本文已影响1人  iChuck

block 的底层实现

void test1() {
    int a = 10;
    void (^block)() = ^{
        NSLog(@"a is %d", a);
    };
    a = 20;
    
    block(); // 10
}

void test2() {
    __block int a = 10;
    
    void (^block)() = ^{
        NSLog(@"a is %d", a);
    };
    
    a = 20;
    
    block(); // 20
}

void test3() {
    static int a = 10;
    
    void (^block) () = ^{
        NSLog(@"a is %d", a);
    };
    
    a = 20;
    
    block; // 20
}

int a = 10;

void test4() {
    void (^block) () = ^{
        NSLog(@"a is %d", a);
    };
    
    a = 20;
    
    block; // 20
}

block 的定义

    <#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
        <#statements#>
    };

block 内存管理

block 的循环引用

retain cycle 例子

block 中循环引用:一个 viewcontroller

@property (nonatomic, strong) HttpRequestHandler *handler;
@property (nonatomic, strong) NSData *data;

    _handler = [HttpRequestHandler sharedManager];
    [_handler downloadData:^(id responseData){
        _data = responseData;
    }];
    
    self 拥有 handler,handler 拥有 block,block 拥有 self(因为使用了 self 的_data 属性,block 会 copy 一份 self)
    解决方法:
    __weak typeof(self) weakSelf = self;
    [_handler downloadData:^(id responseData){
        weakSelf.data = responseData;
    }];

block 中的 weakSelf,是任何时候都需要加的吗?

通过 block 来传值

1. 创建一个 ViewController,在.h 文件里声明一个 block 属性

@interface BlockViewController : ViewController

@property (nonatomic, copy) void (^ valueBlock) (NSString *str);

@end

2. 在.m 文件中实现方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (self.valueBlock) {
        _valueBlock(@"abc");
    }
}

3. 在需要的时候调用方法

BlockViewController *block = [[BlockViewController alloc] init];
block.valueBlock = ^(NSString *str) {
    NSLog(@"blockViewController %@", str);
};
[self presentViewController:block animated:YES completion:nil];

block 作为一个参数使用

1. 在.h 中声明方法
- (void)setText:(void (^)(NSString *str))block;

2. 实现该方法
- (void)setText:(void (^)(NSString *))block {
    block(@"123");
}

3. 调用方法
BlockViewController *block = [[BlockViewController alloc] init];

[self presentViewController:block animated:YES completion:nil];
    
[block setText:^(NSString *str) {
    NSLog(@"blockViewController setText %@",str);
}];

block 作为返回值

1. 在.h 中声明方法
- (BlockViewController * (^)(int))add;

2. 实现该方法
- (BlockViewController *(^)(int))add {
    return ^(int a){
        _result += a;
        return self;
    };
}

3. 调用方法
BlockViewController *block = [[BlockViewController alloc] init];
[self presentViewController:block animated:YES completion:nil];
block.add(10).add(20).add(30);

tip:当一个函数没有参数的,可以吧这个函数看做 get 方法使用点语法来调用
    

block 变量传递

使用 block 有什么好处?使用 NSTimer 写出一个使用 block 显示(在 UILabel 上)秒表的代码。


// YYKit 的一段 timer 封装成 block 回调的代码
+ (void)_yy_ExecBlock:(NSTimer *)timer {
    if ([timer userInfo]) {
        void (^block)(NSTimer *timer) = (void (^)(NSTimer *timer))[timer userInfo];
        block(timer);
    }
}

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
    return [NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(_yy_ExecBlock:) userInfo:[block copy] repeats:repeats];
}

// 使用

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 block:^() {
  weakSelf.secondsLabel.text = ...
} repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

block 和函数很像

使用系统的 block api(如 UIView的 block 动画)是否考虑循环引用的问题?

[UIView animateWithDuration:1 animations:^{
    [self.view layoutIfNeeded];
}];

NSOperationQueue *queue = [NSOperationQueue mainQueue];
[queue addOperationWithBlock:^{
    self.view = [[UIView alloc] init];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:@"NSNotificationName" object:nil queue:queue usingBlock:^(NSNotification * _Nonnull note) {
    self.view = [[UIView alloc] init];
}];
__weak typeof(self) weakSelf = self;
dispatch_group_async(group, queue, ^{
    __weak typeof(self) strongSelf = weakSelf;
    [strongSelf doSomething];
});

__weak typeof(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"NSNotificationName" object:nil queue:queue usingBlock:^(NSNotification * _Nonnull note) {
    __weak typeof(self) strongSelf = weakSelf;
    [strongSelf dismissViewControllerAnimated:YES completion:nil];
}];

self->_observer->block->self 显然是一个循环引用
上一篇下一篇

猜你喜欢

热点阅读