美文网首页iOS程序猿iOS Developer
在Objective-C中self关键字到底是什么

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

作者: Little_Mango | 来源:发表于2017-02-24 18:52 被阅读806次

    在实例方法中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);
        }
    }
    

    相关文章

      网友评论

        本文标题:在Objective-C中self关键字到底是什么

        本文链接:https://www.haomeiwen.com/subject/tabwwttx.html