美文网首页
@property 的本质是什么?ivar、getter、set

@property 的本质是什么?ivar、getter、set

作者: Zorin | 来源:发表于2020-07-08 10:31 被阅读0次

    1. @property 的本质是什么?

    @property = ivar + getter + setter;

    下面解释下:

    “属性” (property)有两大概念:ivar(实例变量)、存取方法(access method = getter + setter)。

    “属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。这个概念已经定型,并且经由“属性”这一特性而成为 Objective-C 2.0 的一部分。 而在正规的 Objective-C 编码风格中,存取方法有着严格的命名规范。 正因为有了这种严格的命名规范,所以 Objective-C 这门语言才能根据名称自动创建出存取方法。其实也可以把属性当做一种关键字,其表示:

    编译器会自动写出一套存取方法,用以访问给定类型中具有给定名称的变量。 所以你也可以这么说:
    @property = getter + setter;

    例如下面这个类:

    @interface Person : NSObject
    @property NSString *firstName;
    @property NSString *lastName;
    @end
    

    上述代码写出来的类与下面这种写法等效:

    @interface Person : NSObject
    - (NSString *)firstName;
    - (void)setFirstName:(NSString *)firstName;
    - (NSString *)lastName;
    - (void)setLastName:(NSString *)lastName;
    @end
    

    property在runtime中是objc_property_t定义如下:

    typedef struct objc_property *objc_property_t;
    

    objc_property是一个结构体,包括name和attributes,定义如下:

    struct property_t {
        const char *name;
        const char *attributes;
    };
    

    而attributes本质是objc_property_attribute_t,定义了property的一些属性,定义如下:

    /// Defines a property attribute
    typedef struct {
        const char *name;           /**< The name of the attribute */
        const char *value;          /**< The value of the attribute (usually empty) */
    } objc_property_attribute_t;
    

    而attributes的具体内容是什么呢?其实,包括:类型,原子性,内存语义和对应的实例变量。

    例如:我们定义一个string的property@property (nonatomic, copy) NSString *string; ,通过 property_getAttributes(property)获取到attributes并打印出来之后的结果为T@"NSString",C,N,V_string

    其中T就代表类型,可参阅Type Encodings,C就代表Copy,N代表nonatomic,V就代表对应的实例变量。


    2. var、getter、setter 是如何生成并添加到这个类中的?

    “自动合成”( autosynthesis)

    完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译 器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。在前例中,会生成两个实例变量,其名称分别为 _firstName 与 _lastName。也可以在类的实现代码里通过 @synthesize 语法来指定实例变量的名字.

    @implementation Person
    @synthesize firstName = _myFirstName;
    @synthesize lastName = _myLastName;
    @end
    

    我为了搞清属性是怎么实现的,曾经反编译过相关的代码,他大致生成了五个东西:

    1. OBJC_IVAR_$类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。
    2. settergetter 方法对应的实现函数
    3. ivar_list :成员变量列表
    4. method_list :方法列表
    5. prop_list :属性列表

    也就是说我们每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.

    相关文章

      网友评论

          本文标题:@property 的本质是什么?ivar、getter、set

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