美文网首页iOS
iOS:@property和@synthesize

iOS:@property和@synthesize

作者: HoooChan | 来源:发表于2019-02-20 11:56 被阅读19次

    定义一个很简单的类:

    // .h
    #import <Foundation/Foundation.h>
    
    @interface SimpleClass : NSObject {
        NSString *simpleName;
    }
    @end
    
    // .m
    #import "SimpleClass.h"
    
    @implementation SimpleClass
    @end
    

    运行clang -rewrite-objc SimpleClass.m查看生成的SimpleClass.cpp文件:

    struct SimpleClass_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString *simpleName;
    };
    
    /* @end */
    
    
    // @implementation SimpleClass
    
    // @end
    

    SimpleClass_IMPL是SimpleClass类的实现,里面保存了simpleName变量,但这个时候没有getter和setter方法。

    我们把{NSString *simpleName;}改成@property (nonatomic, copy) NSString *simpleName;再重新编译:

    struct SimpleClass_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString *_simpleName;
    };
    
    // @property (nonatomic, copy) NSString *simpleName;
    /* @end */
    
    
    // @implementation SimpleClass
    
    
    static NSString * _I_SimpleClass_simpleName(SimpleClass * self, SEL _cmd) {
        return (*(NSString **)((char *)self + OBJC_IVAR_$_SimpleClass$_simpleName));
    }
    
    ...
    
    static void _I_SimpleClass_setSimpleName_(SimpleClass * self, SEL _cmd, NSString *simpleName) {
        objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct SimpleClass, _simpleName), (id)simpleName, 0, 1);
    }
    // @end
    

    可以看到编译器帮我们生成了名为_simpleName的成员变量,同时生成了对应的getter/setter方法。

    getter方法里面利用OBJC_IVAR_$_SimpleClass$_simpleName偏移量来计算_simpleName的位置,来看看OBJC_IVAR_$_SimpleClass$_simpleName的定义:

    extern "C" unsigned long int OBJC_IVAR_$_SimpleClass$_simpleName __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct SimpleClass, _simpleName);
    

    是通过__OFFSETOFIVAR__来计算偏移量的。

    setter方法里面,通过调用objc_setProperty方法来设置值。如果我们把simpleName的属性类型改为strong再重新编译:

    static void _I_SimpleClass_setSimpleName_(SimpleClass * self, SEL _cmd, NSString *simpleName) {
        (*(NSString **)((char *)self + OBJC_IVAR_$_SimpleClass$_simpleName)) = simpleName;
    }
    

    可以看到setter函数的实现也改变了。

    我们在@Implementation里面添加一行代码:

    @implementation SimpleClass
    
    @synthesize simpleName = newSimpleName;
    
    @end
    

    再重新编译,则看到原本的_simpleName改为了newSimpleName:

    extern "C" unsigned long OBJC_IVAR_$_SimpleClass$newSimpleName;
    struct SimpleClass_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString *newSimpleName;
    };
    
    // @property (nonatomic, copy) NSString *simpleName;
    /* @end */
    
    
    // @implementation SimpleClass
    
    // @synthesize simpleName = newSimpleName;
    static NSString * _I_SimpleClass_simpleName(SimpleClass * self, SEL _cmd) {
        return (*(NSString **)((char *)self + OBJC_IVAR_$_SimpleClass$newSimpleName));
    }
    extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
    
    static void _I_SimpleClass_setSimpleName_(SimpleClass * self, SEL _cmd, NSString *simpleName) {
        objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct SimpleClass, newSimpleName), (id)simpleName, 0, 1);
    }
    

    所以可以用@synthesize来修改生成的成员变量的名字

    如果我们定义的属性可读或可写而同时又自己复写了getter或setter方法,这时编译器不会自动帮我们生成成员变量,这时我们需要自己通过@synthesize来添加成员变量。所以当我们手动添加了getter/setter方法时,我们需要利用@synthesize来自动生成成员变量

    在协议和category里面实现了property属性时也不会自动生成成员变量。如果一个类实现了带有property的协议,那它必须自己通过@synthesize来自动生成成员变量

    所以什么时候会用到@synthesize
    1、需要修改成员变量的命名
    2、无法自动生成成员变量

    • 2.1、复写了可读或可写属性的getter或setter方法;
    • 2.2、属性是协议里面定义的

    当我们在子类和父类里面定义相同的属性时,看看会发生什么:

    @interface SimpleClass : NSObject
    @property (nonatomic, copy) NSString *simpleName;
    @end
    
    @interface SubSimpleClass : SimpleClass
    @property (nonatomic, copy) NSString *simpleName;
    @end
    

    编译后的代码:

    struct SimpleClass_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString *_simpleName;
    };
    
    // @property (nonatomic, copy) NSString *simpleName;
    /* @end */
    ...
    struct SubSimpleClass_IMPL {
        struct SimpleClass_IMPL SimpleClass_IVARS;
    };
    
    // @property (nonatomic, copy) NSString *simpleName;
    /* @end */
    
    
    // @implementation SimpleClass
    
    
    static NSString * _I_SimpleClass_simpleName(SimpleClass * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_SimpleClass$_simpleName)); }
    extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
    
    static void _I_SimpleClass_setSimpleName_(SimpleClass * self, SEL _cmd, NSString *simpleName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct SimpleClass, _simpleName), (id)simpleName, 0, 1); }
    // @end
    
    // @implementation SubSimpleClass
    
    // @end
    

    可以看到子类中并没有自动生成成员变量,也没有生成getter/setter方法。

    相关文章

      网友评论

        本文标题:iOS:@property和@synthesize

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