在实例方法中
Self
指代本类的实例对象。
在类方法中Self
指代类对象
上面就是结论,注意一下类的实例对象和类对象(元类的实例对象)的区别。
举个例子来证明
#import "MGExample.h"
@implementation MGExample
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
+ (instancetype)heroWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
@end
上面两个方法一个是实例方法,一个是类方法,在clang -rewrite-objc MGExample.m
之后,代码如下:
static instancetype _I_ MGExample_initWithDict_(MGExample * self, SEL _cmd, NSDictionary *dict) {
if (self = ((MGExample *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("MGExample"))}, sel_registerName("init"))) {
((void (*)(id, SEL, NSDictionary<NSString *,id> *))(void *)objc_msgSend)((id)self, sel_registerName("setValuesForKeysWithDictionary:"), (NSDictionary<NSString *,id> *)dict);
}
return self;
}
static instancetype _C_ MGExample_heroWithDict_(Class self, SEL _cmd, NSDictionary *dict) {
return ((id (*)(id, SEL, NSDictionary *))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("alloc")), sel_registerName("initWithDict:"), (NSDictionary *)dict);
}
从两个方法的第一个传入参数的类型可以很明显得出最上面的结论。
补充一下,类对象的生命周期是从该类载入程序的时候开始,直到程序结束,类对象的生命周期才结束,所以一般不要给类对象设置关联对象,因为这样做之后该关联对象的生命周期会变得非常长,超乎你的想象。以UIGestureRecongzier
分类为例子:
//以下为错误代码
+ (instancetype)bp_recongizerWithActionBlock:(BPGestureBlock)block {
//self指类对象。
objc_setAssociatedObject(self, &blockKey, block, OBJC_ASSOCIATION_COPY);
return [[self alloc] initWithTarget:self action:@selector(bp_block:)];
}
+ (void)bp_block:(UIGestureRecognizer *)gest {
BPGestureBlock block = objc_getAssociatedObject(self, &blockKey);
if (block) {
block(gest);
}
}
如果像上面那样写,则会造成block被类对象持有,导致资源得不到及时的释放,或者说不像我们期待的那样随着UIGestureRecognizer
实例对象的释放而释放,因为关联block的对象是类对象而不是实例对象。正确的写法中的一种可以像下面的示例:
+ (instancetype)bp_recognizerWithBlock:(BPGestureBlock)block {
return [[self alloc] initWithBlock:block];
}
- (instancetype)initWithBlock:(BPGestureBlock)block {
self = [self init];
if (self) {
objc_setAssociatedObject(self, &blockKey, block, OBJC_ASSOCIATION_COPY);
[self addTarget:self action:@selector(p_handleBlock)];
}
return self;
}
- (void)p_handleBlock {
BPGestureBlock block = objc_getAssociatedObject(self, &blockKey);
if (block) {
block(self);
}
}
网友评论