iOS block相关

block中访问成员变量与self的引用

2018-09-28  本文已影响39人  麻辣香锅加特辣

在block中直接访问成员变量和通过self.访问,block都会强引用self
两种方式对比:
通过 命令:clang -rewrite-objc Person.m 将oc代码转换为c++代码

  1. 直接访问成员变量
#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, strong) NSString *name123;

@end

#import "Person.h"

@interface Person() {
    int age123;
}
@end

@implementation Person

- (void)test {
    void (^myblock) (void) = ^{
        NSLog(@"%d", age123);
    };

    myblock();
}
@end

转换为c++的代码:

// @implementation Person
struct __Person__test_block_impl_0 {
  struct __block_impl impl;
  struct __Person__test_block_desc_0* Desc;
  //这里有个self
  Person *self;
  __Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *_self, int flags=0) : self(_self) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __Person__test_block_func_0(struct __Person__test_block_impl_0 *__cself) {
      Person *self = __cself->self; // bound by copy

       //猜测是通过self + 偏移量访问到成员变量
       NSLog((NSString *)&__NSConstantStringImpl__var_folders_y6_mv_x0lbx2qs9dvbg7g9_sk780000gn_T_Person_bd97ae_mi_0, 
            (*(int *)((char *)self + OBJC_IVAR_$_Person$age123)));
    }
  1. 通过点语法访问
@implementation Person

- (void)test {
    void (^myblock) (void) = ^{
        NSLog(@"%@", self.name123);
    };
    
    myblock();
}
@end

转换为c++的代码:

// @implementation Person


struct __Person__test_block_impl_0 {
  struct __block_impl impl;
  struct __Person__test_block_desc_0* Desc;
  //这里也有个self
  Person *self;
  __Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *_self, int flags=0) : self(_self) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __Person__test_block_func_0(struct __Person__test_block_impl_0 *__cself) {
     Person *self = __cself->self; // bound by copy

     //通过消息发送的方式,调用getter方法访问成员变量
     NSLog((NSString *)&__NSConstantStringImpl__var_folders_y6_mv_x0lbx2qs9dvbg7g9_sk780000gn_T_Person_487e48_mi_0, 
          ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("name123")));
    }

通过转换后的代码可以看出来,无论通过那种方式访问最终都需要使用self,所以block都会强引用self。

上一篇下一篇

猜你喜欢

热点阅读