在Objective-C中self关键字到底是什么

在实例方法中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);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容