在block中直接访问成员变量和通过self.访问,block都会强引用self
两种方式对比:
通过 命令:clang -rewrite-objc Person.m 将oc代码转换为c++代码
- 直接访问成员变量
#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)));
}
- 通过点语法访问
@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。
网友评论