iOS 开发 Objective-C

iOS 底层 day10 block 的 __block 和 循

2020-09-01  本文已影响0人  望穿秋水小作坊

一、__block 的本质

1. 观察如下代码,会报错吗?如果想在 block 内修改 age 的值,有哪三种方式?
typedef void (^SPBlock)(void);
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 10;
        SPBlock block = ^ {
            age = 20;
            NSLog(@"%d",age);
        };
        block();
        NSLog(@"%d",age);
    }
    return 0;
}
2. __block 修饰符是什么?
3. 下面代码中的 array没有使用__block` 修饰,能够正常使用吗?
typedef void (^SPBlock)(void);
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableArray *array = [[NSMutableArray alloc] init];
        SPBlock block = ^ {
            [array addObject:@"1"];
        };
        block();
        NSLog(@"%@",array);
    }
    return 0;
}
4. __block 修饰 auto 的 非OC 对象变量,本质做了什么事情?
修饰一般变量代码逻辑图 forwarding图解
5. 在问题 4 中,那么多 age,我们如何确定拿到的 age 是哪个 age 呢?
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __Block_byref_age_0 {
 void *__isa;  // 8字节
 struct __Block_byref_age_0 *__forwarding;// 8字节
 int __flags; // 4字节
 int __size; // 4字节
 int age; // 这个 age 相对于__isa的地址需要加24 字节
};

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
};


struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  struct __Block_byref_age_0 *age; // by ref
};


typedef void (^SPBlock)(void);
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        __block int age = 10;
        SPBlock block = ^ {
            age = 20;
        };
        struct __main_block_impl_0 lsBlock =*(__bridge struct __main_block_impl_0*)block;
        NSLog(@"断点处");
    }
    return 0;
}
(lldb) p/x lsBlock->age
(__Block_byref_age_0 *) $7 = 0x0000000100525260
  Fix-it applied, fixed expression was: 
    lsBlock.age
(lldb) p/x &age
(int *) $8 = 0x0000000100525278
(lldb) p/x 0x0000000100525260 +  0x18
(long) $9 = 0x0000000100525278
6. __block 修饰 oc对象,比较复杂,暂时先不讨论,后面有需要再补充。

二、block 相关的循环引用

1. 下面代码,会导致循环引用吗?
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];
        person.age = 20;
        person.block = ^{
            NSLog(@"Age is %d", person.age);
        };
        
        person.block();
    }
    return 0;
}
2. 问题 1 你有哪几种方案解决循环引用?
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        __block Person *person = [[Person alloc] init];
        person.age = 20;
        person.block = ^{
            NSLog(@"Age is %d", person.age);
            person = nil;
        };
        person.block();
    }
    return 0;
}
3. __weak__unsafe_unretained 都能解决循环引用,那么有什么区别?
4. 下面的这种写法,经常见到,__strong 有什么作用?
- (void)test {
    __weak typeof(self) weakSelf = self;
    self.block = ^{
        __strong typeof(self) strongSelf = weakSelf;
        NSLog(@"Age is %d", strongSelf->_age);
    };
}
上一篇 下一篇

猜你喜欢

热点阅读