其间输出类实例变量的切切实实代码,未经小编许可

前言

前几日有人问我1个题材:为啥分类无法活动成立get
set方法。老实说,作者一向没有去思维过这些标题。于是这一次通过代码实践跟runtime源码来研商那几个标题。

本文作者: 伯乐在线
林欣达
。未经小编许可,禁止转发!
欢迎到场伯乐在线 专辑作者

预备干活

为了能压缩输出类数据的代码工作,小编依照NSObject的分类封装了一套代码

里面输出类实例变量的有血有肉代码:

  • (void)logIvarsWithExpReg: (NSString *)expReg customed: (BOOL)customed
    {
    [NSObject kRecordOBJ];
    unsigned int ivarCount;
    Ivar * ivars = class_copyIvarList([self class], &ivarCount);
    for (int idx = 0; idx < ivarCount; idx++) {
    Ivar ivar = ivars[idx];
    NSString * ivarName = [NSString stringWithUTF8String:
    ivar_getName(ivar)];
    if (customed && [kOBJIvarNames containsObject: ivarName]) {
    continue;
    }
    if (expReg && !kValidExpReg(ivarName, expReg)) {
    continue;
    }
    printf(“ivar: %s — %s\n”, NSStringFromClass([self
    class]).UTF8String, ivarName.UTF8String);
    }
    free(ivars);
    }
    +(void)kRecordOBJ采用dispatch_once的艺术将NSObject存在的数目存储到几个数组中,用来裁撤父类的数码输出

前言

类的质量

  • 好端端创立类
    @interface Person: NSObject {
    int _pId;
    }

    @property (nonatomic, copy) NSString * name;
    @property (nonatomic, assign) NSUInteger age;
    
    @end
    
    int main(int argc, char * argv[]) {
        @autoreleasepool {
            Person * p = [[Person alloc] init];
            [p logCustomIvars];
            [p logCustomMethods];
            [p logCustomProperties];
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }
    

运作结果:属性nameage转移了对应的_propertyName的实例变量以及settergetter

  • 动态生成属性age
    @implementation Person
    @dynamic age;

    @end
    

运作结果:缺少了_age变量以及对应的setAge:age方法

  • 手动达成setter/getter
    @implemetation Person
    @dynamic age;

    - (void)setAge: (NSUInteger)age {}
    - (NSUInteger)age { return 18; }
    
    @end
    

出口结果:未变动_age实例变量

  • 手动已毕_pIdsetter/getter
    @implemetation Person
    @dynamic age;

    - (void)setAge: (NSUInteger)age {}
    - (NSUInteger)age { return 18; }
    
    - (void)setPId: (int)pId { _pId = pId; }
    - (int)pId { return _pId; }      
    
    @end
    
    [p setValueForKey: @"pId"];
    

运维结果:KVC的拜会会触发setter方法,_pId除外无法透过点语法访问外,其他表现与@property无异

经过地点的几段试验,可以得出@property的公式:

明日有人问作者3个难题:为何分类不可能活动创设get
set方法。老实说,我向来不曾去切磋过那些标题。于是本次通过代码实践跟runtime源码来探索那么些难点。

分类属性

  • 分类中添加weighheight属性
    @interface Person (category)

    @property (nonatomic, assign) CGFloat weigh;
    @property (nonatomic, assign) CGFloat height;
    
    @end
    

运行结果:weighheight未生成实例变量以及对应的setter/getter,与@dynamic修饰的age突显同样

  • 使用@synthesize自动合成setter/getter措施时编译报错

  • 手动完成setter/getter
    @implemetation Person (category)

    - (void)setWeigh: (CGFloat)weigh {}
    - (CGFloat)weigh { return 150; }
    
    @end
    

运作结果:与@dynamic age后重写其setter/getter彰显同样

  • 动态绑定属性来落到实处setter/getter
    void * kHeightKey = &kHeightKey;
    @implemetation Person (category)

    - (void)setWeigh: (CGFloat)weigh {}
    - (CGFloat)weigh { return 150; }
    
    - (void)setHeight: (CGFloat)height {
        objc_setAssociatedObject(self, kHeightKey, @(height), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    - (CGFloat)height { 
        return return [objc_getAssociatedObject(self, kHeightKey) doubleValue];;
    }
    
    @end
    
    [p logCustomIvars]
    [p logCustomMethods];
    [p logCustomProperties];
    
    CGFloat height = 180;
    p.height = 180;
    height = p.height;
    
    [p logCustomIvars]
    [p logCustomMethods];
    [p logCustomProperties];
    

运作结果:动态绑定前后ivar从没生出其余变更

经过代码实验,能够得出下边八个结论:

  • 分类属性约等于@dynamic property
  • 缺少ivar的图景下无法运用@synthesize自动合成属性

以及一个揣摸:

  • 在类成就加载后不能够继续拉长ivar

通过runtime动态成立类验证猜度:

int main(int argc, char * argv[]) {

    NSString * className = @"Custom";
    Class customClass = objc_allocateClassPair([NSObject class], className.UTF8String, 0);
    class_addIvar(customClass, @"ivar1".UTF8String, sizeof(NSString *), 0, "@");
    objc_property_attribute_t type1 = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership1 = { "C", "N" };
    objc_property_attribute_t atts1[] = { type1, ownership1 };
    class_addProperty(customClass, "property1", atts1, 2);

    objc_registerClassPair(customClass);
    id instance = [[customClass alloc] init];
    NSLog(@"\nLog Ivars ===================");
    [instance logCustomIvars];
    NSLog(@"\nLog methods ===================");
    [instance logCustomMethods];
    NSLog(@"\nLog properties ===================");
    [instance logCustomProperties];

    class_addIvar(customClass, @"ivar2".UTF8String, sizeof(NSString *), 0, "@");
    objc_property_attribute_t type2 = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership2 = { "C", "N" };
    objc_property_attribute_t atts2[] = { type2, ownership2 };
    class_addProperty(customClass, "property2", atts2, 2);
    instance = [[customClass alloc] init];
    NSLog(@"\nLog Ivars ===================");
    [instance logCustomIvars];
    NSLog(@"\nLog methods ===================");
    [instance logCustomMethods];
    NSLog(@"\nLog properties ===================");
    [instance logCustomProperties];
}

运营结果:在调用class_registerClassPair后,添加ivar失败

居安虑危工作

为了能压缩输出类数据的代码工作,我根据NSObject的分类封装了一套代码

 皇冠现金app 1

其间输出类实例变量的切切实实代码:

Objective-C

– (void)logIvarsWithExpReg: (NSString *)expReg customed:
(BOOL)customed { [NSObject kRecordOBJ]; unsigned int ivarCount; Ivar
* ivars = class_copyIvarList([self class], &ivarCount); for (int idx
= 0; idx < ivarCount; idx++) { Ivar ivar = ivars[idx]; NSString *
ivarName = [NSString stringWithUTF8String: ivar_getName(ivar)]; if
(customed && [kOBJIvarNames containsObject: ivarName]) { continue; }
if (expReg && !kValidExpReg(ivarName, expReg)) { continue; }
printf(“ivar: %s — %s\n”, NSStringFromClass([self
class]).UTF8String, ivarName.UTF8String); } free(ivars); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
– (void)logIvarsWithExpReg: (NSString *)expReg customed: (BOOL)customed {
    [NSObject kRecordOBJ];
    unsigned int ivarCount;
    Ivar * ivars = class_copyIvarList([self class], &ivarCount);
    for (int idx = 0; idx < ivarCount; idx++) {
        Ivar ivar = ivars[idx];
        NSString * ivarName = [NSString stringWithUTF8String: ivar_getName(ivar)];
        if (customed && [kOBJIvarNames containsObject: ivarName]) {
            continue;
        }
        if (expReg && !kValidExpReg(ivarName, expReg)) {
            continue;
        }
        printf("ivar: %s — %s\n", NSStringFromClass([self class]).UTF8String, ivarName.UTF8String);
    }
    free(ivars);
}

+(void)kRecordOBJ采用dispatch_once的主意将NSObject留存的数码存储到多个数组中,用来排除父类的多寡输出

从源码解析

objc_class的构造体定义如下:

struct objc_class : objc_object {
    Class superclass;
    const char *name;
    uint32_t version;
    uint32_t info;
    uint32_t instance_size;
    struct old_ivar_list *ivars;
    struct old_method_list **methodLists;
    Cache cache;
    struct old_protocol_list *protocols;
    // CLS_EXT only
    const uint8_t *ivar_layout;
    struct old_class_ext *ext;
}

ps: 在新本子中结构体内部已经暴发了大改,但是中间的习性大致上仍是那些

这里面有个第一的性情ivar_layout,顾名思义存放的是变量的职分属性,与之对应的还有2个weakIvarLayout变量,不过在私下认同结构中尚无出现。那三个属性用来记录ivar哪些是strong或者weak,而那一个记录操作在runtime等级已经被确定好。正由于这样,那极有只怕是ivar无法在类被加载后继续拉长的缘故之一。ivar_layout的更加多明白可以参见Objective-C
Class Ivar
layout
一文

import操作扶助编译检查和链接进度,然则在category的加载进程中,不会将扩大的始末添加到原始的类社团中。runtime对于category的加载进度可以简简单单的分成上边几步(摘自objc
category的密码
):

  • objc runtime的加载入口是二个叫_objc_init的方法,在library加载前由libSystem dyld调用,举行先河化操作
  • 调用map_images主意将文件中的image map到内存
  • 调用_read_images措施开首化map后的image,那之中干了重重的事情,像load怀有的类、协议和category,著名的+ load措施就是这一步调用的
    -仔细看category的初阶化,循环调用了_getObjc2CategoryList方法,那么些艺术拿出去看看:
  • .…

这一体的历程暴发在_objc_init函数中,函数完结如下

简易的话在load_images函数中最终会走到上面的代码调用来加载所有的类以及类的归类

按照地点的代码加上runtime的加载顺序,可以持续推出:

  • @dynamic实质上是将品质的加载推迟到类加载成功后

除此以外,前面也说过在缺乏ivar的动静下不可以自动合成setter/getter,除了category自己是不被添加到类社团中的,所以不可以利用类社团的ivar合成属性外,还有分类本人结构的标题

struct category_t {
    const char *name;    ///  类名
    classref_t cls;  ///  类指针
    struct method_list_t *instanceMethods;  ///  实例方法
    struct method_list_t *classMethods;  ///  类方法
    struct protocol_list_t *protocols;  ///  扩展的协议
    struct property_list_t *instanceProperties;  ///  扩展属性

    method_list_t *methodsForMeta(bool isMeta) { ... }
    property_list_t *propertiesForMeta(bool isMeta) { ... }
};

可以看到分类布局自己是不存在ivar的器皿的,由此缺少了自动合成属性的条件。最终还有贰个题目,大家在动用objc_associate星罗棋布函数绑定属性的时候那么些变量存储在了什么地方?

类的性情

  • 健康创制类
@interface Person: NSObject { int \_pId; } @property (nonatomic,
copy) NSString \* name; @property (nonatomic, assign) NSUInteger
age; @end int main(int argc, char \* argv\[\]) { @autoreleasepool {
Person \* p = \[\[Person alloc\] init\]; \[p logCustomIvars\]; \[p
logCustomMethods\]; \[p logCustomProperties\]; return
UIApplicationMain(argc, argv, nil, NSStringFromClass(\[AppDelegate
class\])); } }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-6">
6
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-8">
8
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-10">
10
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-11">
11
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-12">
12
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-13">
13
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-14">
14
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-15">
15
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-16">
16
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f54772087575-17">
17
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f54772087575-18">
18
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f54772087575-1" class="crayon-line">
@interface Person: NSObject {
</div>
<div id="crayon-5a719fb105f54772087575-2" class="crayon-line crayon-striped-line">
    int _pId;
</div>
<div id="crayon-5a719fb105f54772087575-3" class="crayon-line">
}
</div>
<div id="crayon-5a719fb105f54772087575-4" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5a719fb105f54772087575-5" class="crayon-line">
@property (nonatomic, copy) NSString * name;
</div>
<div id="crayon-5a719fb105f54772087575-6" class="crayon-line crayon-striped-line">
@property (nonatomic, assign) NSUInteger age;
</div>
<div id="crayon-5a719fb105f54772087575-7" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f54772087575-8" class="crayon-line crayon-striped-line">
@end
</div>
<div id="crayon-5a719fb105f54772087575-9" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f54772087575-10" class="crayon-line crayon-striped-line">
int main(int argc, char * argv[]) {
</div>
<div id="crayon-5a719fb105f54772087575-11" class="crayon-line">
    @autoreleasepool {
</div>
<div id="crayon-5a719fb105f54772087575-12" class="crayon-line crayon-striped-line">
        Person * p = [[Person alloc] init];
</div>
<div id="crayon-5a719fb105f54772087575-13" class="crayon-line">
        [p logCustomIvars];
</div>
<div id="crayon-5a719fb105f54772087575-14" class="crayon-line crayon-striped-line">
        [p logCustomMethods];
</div>
<div id="crayon-5a719fb105f54772087575-15" class="crayon-line">
        [p logCustomProperties];
</div>
<div id="crayon-5a719fb105f54772087575-16" class="crayon-line crayon-striped-line">
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
</div>
<div id="crayon-5a719fb105f54772087575-17" class="crayon-line">
    }
</div>
<div id="crayon-5a719fb105f54772087575-18" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>


运行结果:属性`name`和`age`生成了对应的`_propertyName`的实例变量以及`setter`和`getter`
 [![](http://jbcdn2.b0.upaiyun.com/2017/01/d0cc11aee6072825c5b406f96ab56eba.jpg)](http://jbcdn2.b0.upaiyun.com/2017/01/d0cc11aee6072825c5b406f96ab56eba.jpg)
  • 动态生成属性age
Objective-C

@implementation Person &lt;a
href='http://www.jobbole.com/members/Dynamic2016'&gt;@dynamic&lt;/a&gt;
age; @end

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f5d792222330-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f5d792222330-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f5d792222330-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f5d792222330-4">
4
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f5d792222330-1" class="crayon-line">
@implementation Person
</div>
<div id="crayon-5a719fb105f5d792222330-2" class="crayon-line crayon-striped-line">
&lt;a href='http://www.jobbole.com/members/Dynamic2016'&gt;@dynamic&lt;/a&gt; age;      
</div>
<div id="crayon-5a719fb105f5d792222330-3" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f5d792222330-4" class="crayon-line crayon-striped-line">
@end
</div>
</div></td>
</tr>
</tbody>
</table>


运行结果:缺少了`_age`变量以及对应的`setAge:`和`age`方法
 [![](http://jbcdn2.b0.upaiyun.com/2017/01/608a52649a1a15b8f3cb992ff312c098.jpg)](http://jbcdn2.b0.upaiyun.com/2017/01/608a52649a1a15b8f3cb992ff312c098.jpg)
  • 手动完结setter/getter
Objective-C

@implemetation Person &lt;a
href='http://www.jobbole.com/members/Dynamic2016'&gt;@dynamic&lt;/a&gt;
age; - (void)setAge: (NSUInteger)age {} - (NSUInteger)age { return
18; } @end

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f65161276016-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f65161276016-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f65161276016-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f65161276016-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f65161276016-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f65161276016-6">
6
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f65161276016-7">
7
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f65161276016-1" class="crayon-line">
@implemetation Person
</div>
<div id="crayon-5a719fb105f65161276016-2" class="crayon-line crayon-striped-line">
&lt;a href='http://www.jobbole.com/members/Dynamic2016'&gt;@dynamic&lt;/a&gt; age;
</div>
<div id="crayon-5a719fb105f65161276016-3" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f65161276016-4" class="crayon-line crayon-striped-line">
- (void)setAge: (NSUInteger)age {}
</div>
<div id="crayon-5a719fb105f65161276016-5" class="crayon-line">
- (NSUInteger)age { return 18; }
</div>
<div id="crayon-5a719fb105f65161276016-6" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5a719fb105f65161276016-7" class="crayon-line">
@end
</div>
</div></td>
</tr>
</tbody>
</table>


输出结果:未生成`_age`实例变量
 [![](http://jbcdn2.b0.upaiyun.com/2017/01/c9238ae41436d501fb5b42334c74b7ab.jpg)](http://jbcdn2.b0.upaiyun.com/2017/01/c9238ae41436d501fb5b42334c74b7ab.jpg)
  • 手动已毕_pIdsetter/getter
Objective-C

@implemetation Person &lt;a
href='http://www.jobbole.com/members/Dynamic2016'&gt;@dynamic&lt;/a&gt;
age; - (void)setAge: (NSUInteger)age {} - (NSUInteger)age { return
18; } - (void)setPId: (int)pId { \_pId = pId; } - (int)pId { return
\_pId; } @end \[p setValueForKey: @"pId"\];

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f6c253478127-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f6c253478127-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f6c253478127-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f6c253478127-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f6c253478127-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f6c253478127-6">
6
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f6c253478127-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f6c253478127-8">
8
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f6c253478127-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f6c253478127-10">
10
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f6c253478127-11">
11
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f6c253478127-12">
12
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f6c253478127-1" class="crayon-line">
@implemetation Person
</div>
<div id="crayon-5a719fb105f6c253478127-2" class="crayon-line crayon-striped-line">
&lt;a href='http://www.jobbole.com/members/Dynamic2016'&gt;@dynamic&lt;/a&gt; age;
</div>
<div id="crayon-5a719fb105f6c253478127-3" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f6c253478127-4" class="crayon-line crayon-striped-line">
- (void)setAge: (NSUInteger)age {}
</div>
<div id="crayon-5a719fb105f6c253478127-5" class="crayon-line">
- (NSUInteger)age { return 18; }
</div>
<div id="crayon-5a719fb105f6c253478127-6" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5a719fb105f6c253478127-7" class="crayon-line">
- (void)setPId: (int)pId { _pId = pId; }
</div>
<div id="crayon-5a719fb105f6c253478127-8" class="crayon-line crayon-striped-line">
- (int)pId { return _pId; }      
</div>
<div id="crayon-5a719fb105f6c253478127-9" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f6c253478127-10" class="crayon-line crayon-striped-line">
@end
</div>
<div id="crayon-5a719fb105f6c253478127-11" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f6c253478127-12" class="crayon-line crayon-striped-line">
[p setValueForKey: @&quot;pId&quot;];
</div>
</div></td>
</tr>
</tbody>
</table>


运行结果:`KVC`的访问会触发`setter`方法,`_pId`除了无法通过点语法访问外,其他表现与`@property`无异
 [![](http://jbcdn2.b0.upaiyun.com/2017/01/ab318eccdd6c7cedbd78fe4913695717.jpg)](http://jbcdn2.b0.upaiyun.com/2017/01/ab318eccdd6c7cedbd78fe4913695717.jpg)

经过地方的几段试验,可以汲取@property的公式:

 皇冠现金app 2

总结

先是,iOS的归类在runtime落到实处的结构体中并不设有Ivar品类的容器,紧缺了自动合成setter以及getter的必要条件,由此在分拣中扬言的属性暗许为@dynamic修饰。

其次,OC本身是一门原型语言,对象和类原型很像。类对象实施alloc艺术就如原型方式中的copy操作一样,类保存了copy所需的实例音讯,那个消息内存新闻在runtime加载时就被定位了,没有增添Ivar的条件。(感谢大表哥的科普)

最后,在runtime中留存三个种类为AssociationHashMap的哈希映射表保存着对象动态增进的习性,各种对象以本身地址为key维护着3个绑定属性表,大家动态增加的性质就都存储在这一个表里,这也是动态增进property能得逞的功底。

上一篇:闲聊内存管理

转发请申明原文地址及笔者

分拣属性

  • 分类中添加weighheight皇冠现金app,属性
@interface Person (category) @property (nonatomic, assign) CGFloat
weigh; @property (nonatomic, assign) CGFloat height; @end

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f73962468419-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f73962468419-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f73962468419-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f73962468419-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f73962468419-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f73962468419-6">
6
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f73962468419-1" class="crayon-line">
@interface Person (category)
</div>
<div id="crayon-5a719fb105f73962468419-2" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5a719fb105f73962468419-3" class="crayon-line">
@property (nonatomic, assign) CGFloat weigh;
</div>
<div id="crayon-5a719fb105f73962468419-4" class="crayon-line crayon-striped-line">
@property (nonatomic, assign) CGFloat height;
</div>
<div id="crayon-5a719fb105f73962468419-5" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f73962468419-6" class="crayon-line crayon-striped-line">
@end
</div>
</div></td>
</tr>
</tbody>
</table>


运行结果:`weigh`和`height`未生成实例变量以及对应的`setter/getter`,与`@dynamic`修饰的`age`表现一致
 [![](http://jbcdn2.b0.upaiyun.com/2017/01/4356fe5d1bfe993bc770db31e986b5be.jpg)](http://jbcdn2.b0.upaiyun.com/2017/01/4356fe5d1bfe993bc770db31e986b5be.jpg)
  • 使用@synthesize自动合成setter/getter办法时编译报错
     皇冠现金app 3

  • 手动完成setter/getter
    @implemetation Person (category)

\- (void)setWeigh: (CGFloat)weigh {} - (CGFloat)weigh { return 150;
} @end

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f7a874685202-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f7a874685202-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f7a874685202-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f7a874685202-4">
4
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f7a874685202-1" class="crayon-line">
- (void)setWeigh: (CGFloat)weigh {}
</div>
<div id="crayon-5a719fb105f7a874685202-2" class="crayon-line crayon-striped-line">
- (CGFloat)weigh { return 150; }
</div>
<div id="crayon-5a719fb105f7a874685202-3" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f7a874685202-4" class="crayon-line crayon-striped-line">
@end
</div>
</div></td>
</tr>
</tbody>
</table>


运行结果:与`@dynamic age`后重写其`setter/getter`表现一致
  • 动态绑定属性来促成setter/getter
void \* kHeightKey = &kHeightKey; @implemetation Person (category) -
(void)setWeigh: (CGFloat)weigh {} - (CGFloat)weigh { return 150; } -
(void)setHeight: (CGFloat)height { objc\_setAssociatedObject(self,
kHeightKey, @(height), OBJC\_ASSOCIATION\_RETAIN\_NONATOMIC); } -
(CGFloat)height { return return \[objc\_getAssociatedObject(self,
kHeightKey) doubleValue\];; } @end \[p logCustomIvars\] \[p
logCustomMethods\]; \[p logCustomProperties\]; CGFloat height = 180;
p.height = 180; height = p.height; \[p logCustomIvars\] \[p
logCustomMethods\]; \[p logCustomProperties\];

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-6">
6
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-8">
8
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-10">
10
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-11">
11
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-12">
12
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-13">
13
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-14">
14
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-15">
15
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-16">
16
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-17">
17
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-18">
18
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-19">
19
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-20">
20
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-21">
21
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-22">
22
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-23">
23
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-24">
24
</div>
<div class="crayon-num" data-line="crayon-5a719fb105f80024507600-25">
25
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a719fb105f80024507600-26">
26
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a719fb105f80024507600-1" class="crayon-line">
void * kHeightKey = &amp;kHeightKey;
</div>
<div id="crayon-5a719fb105f80024507600-2" class="crayon-line crayon-striped-line">
@implemetation Person (category)
</div>
<div id="crayon-5a719fb105f80024507600-3" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f80024507600-4" class="crayon-line crayon-striped-line">
- (void)setWeigh: (CGFloat)weigh {}
</div>
<div id="crayon-5a719fb105f80024507600-5" class="crayon-line">
- (CGFloat)weigh { return 150; }
</div>
<div id="crayon-5a719fb105f80024507600-6" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5a719fb105f80024507600-7" class="crayon-line">
- (void)setHeight: (CGFloat)height {
</div>
<div id="crayon-5a719fb105f80024507600-8" class="crayon-line crayon-striped-line">
    objc_setAssociatedObject(self, kHeightKey, @(height), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
</div>
<div id="crayon-5a719fb105f80024507600-9" class="crayon-line">
}
</div>
<div id="crayon-5a719fb105f80024507600-10" class="crayon-line crayon-striped-line">
- (CGFloat)height { 
</div>
<div id="crayon-5a719fb105f80024507600-11" class="crayon-line">
    return return [objc_getAssociatedObject(self, kHeightKey) doubleValue];;
</div>
<div id="crayon-5a719fb105f80024507600-12" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5a719fb105f80024507600-13" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f80024507600-14" class="crayon-line crayon-striped-line">
@end
</div>
<div id="crayon-5a719fb105f80024507600-15" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f80024507600-16" class="crayon-line crayon-striped-line">
[p logCustomIvars]
</div>
<div id="crayon-5a719fb105f80024507600-17" class="crayon-line">
[p logCustomMethods];
</div>
<div id="crayon-5a719fb105f80024507600-18" class="crayon-line crayon-striped-line">
[p logCustomProperties];
</div>
<div id="crayon-5a719fb105f80024507600-19" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f80024507600-20" class="crayon-line crayon-striped-line">
CGFloat height = 180;
</div>
<div id="crayon-5a719fb105f80024507600-21" class="crayon-line">
p.height = 180;
</div>
<div id="crayon-5a719fb105f80024507600-22" class="crayon-line crayon-striped-line">
height = p.height;
</div>
<div id="crayon-5a719fb105f80024507600-23" class="crayon-line">
 
</div>
<div id="crayon-5a719fb105f80024507600-24" class="crayon-line crayon-striped-line">
[p logCustomIvars]
</div>
<div id="crayon-5a719fb105f80024507600-25" class="crayon-line">
[p logCustomMethods];
</div>
<div id="crayon-5a719fb105f80024507600-26" class="crayon-line crayon-striped-line">
[p logCustomProperties];
</div>
</div></td>
</tr>
</tbody>
</table>


运行结果:动态绑定前后`ivar`没有发生任何变化
 [![](http://jbcdn2.b0.upaiyun.com/2017/01/15130c8c05a1b8ab7a02421764c1d1c4.jpg)](http://jbcdn2.b0.upaiyun.com/2017/01/15130c8c05a1b8ab7a02421764c1d1c4.jpg)

由此代码实验,可以得出上面多个结论:

  • 分类属性约等于@dynamic property
  • 缺少ivar的图景下不能使用@synthesize自动合成属性

以及一个狐疑:

  • 在类成就加载后无法继续累加ivar

透过runtime动态创造类验证预计:

int main(int argc, char * argv[]) { NSString * className =
@”Custom”; Class customClass = objc_allocateClassPair([NSObject
class], className.UTF8String, 0); class_addIvar(customClass,
@”ivar1″.UTF8String, sizeof(NSString *), 0, “@”);
objc_property_attribute_t type1 = { “T”, “@\”NSString\”” };
objc_property_attribute_t ownership1 = { “C”, “N” };
objc_property_attribute_t atts1[] = { type1, ownership1 };
class_addProperty(customClass, “property1″, atts1, 2);
objc_registerClassPair(customClass); id instance = [[customClass
alloc] init]; NSLog(@”\nLog Ivars ===================”); [instance
logCustomIvars]; NSLog(@”\nLog methods ===================”);
[instance logCustomMethods]; NSLog(@”\nLog properties
===================”); [instance logCustomProperties];
class_addIvar(customClass, @”ivar2″.UTF8String, sizeof(NSString *), 0,
“@”); objc_property_attribute_t type2 = { “T”, “@\”NSString\”” };
objc_property_attribute_t ownership2 = { “C”, “N” };
objc_property_attribute_t atts2[] = { type2, ownership2 };
class_addProperty(customClass, “property2″, atts2, 2); instance =
[[customClass alloc] init]; NSLog(@”\nLog Ivars
===================”); [instance logCustomIvars]; NSLog(@”\nLog
methods ===================”); [instance logCustomMethods];
NSLog(@”\nLog properties ===================”); [instance
logCustomProperties]; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int main(int argc, char * argv[]) {
 
    NSString * className = @"Custom";
    Class customClass = objc_allocateClassPair([NSObject class], className.UTF8String, 0);
    class_addIvar(customClass, @"ivar1".UTF8String, sizeof(NSString *), 0, "@");
    objc_property_attribute_t type1 = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership1 = { "C", "N" };
    objc_property_attribute_t atts1[] = { type1, ownership1 };
    class_addProperty(customClass, "property1", atts1, 2);
 
    objc_registerClassPair(customClass);
    id instance = [[customClass alloc] init];
    NSLog(@"\nLog Ivars ===================");
    [instance logCustomIvars];
    NSLog(@"\nLog methods ===================");
    [instance logCustomMethods];
    NSLog(@"\nLog properties ===================");
    [instance logCustomProperties];
 
    class_addIvar(customClass, @"ivar2".UTF8String, sizeof(NSString *), 0, "@");
    objc_property_attribute_t type2 = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership2 = { "C", "N" };
    objc_property_attribute_t atts2[] = { type2, ownership2 };
    class_addProperty(customClass, "property2", atts2, 2);
    instance = [[customClass alloc] init];
    NSLog(@"\nLog Ivars ===================");
    [instance logCustomIvars];
    NSLog(@"\nLog methods ===================");
    [instance logCustomMethods];
    NSLog(@"\nLog properties ===================");
    [instance logCustomProperties];
}

运行结果:在调用class_registerClassPair后,添加ivar失败

 皇冠现金app 4

从源码解析

objc_class的布局体定义如下:

struct objc_class : objc_object { Class superclass; const char *name;
uint32_t version; uint32_t info; uint32_t instance_size; struct
old_ivar_list *ivars; struct old_method_list **methodLists; Cache
cache; struct old_protocol_list *protocols; // CLS_EXT only const
uint8_t *ivar_layout; struct old_class_ext *ext; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct objc_class : objc_object {
    Class superclass;
    const char *name;
    uint32_t version;
    uint32_t info;
    uint32_t instance_size;
    struct old_ivar_list *ivars;
    struct old_method_list **methodLists;
    Cache cache;
    struct old_protocol_list *protocols;
    // CLS_EXT only
    const uint8_t *ivar_layout;
    struct old_class_ext *ext;
}

ps: 在新本子中结构体内部已经暴发了大改,可是其中的质量大概上仍是那一个

那里面有个至关紧要的个性ivar_layout,顾名思义存放的是变量的职位属性,与之相应的还有多个weakIvarLayout变量,然则在专擅认同结构中从未出现。这七个属性用来记录ivar哪些是strong或者weak,而这么些记录操作在runtime等级已经被确定好。正由于那样,那极有大概是ivar惊慌失措在类被加载后继续增进的原因之一。ivar_layout的越多询问可以参见Objective-C
Class Ivar
layout
一文

import操作协助编译检查和链接进程,然则在category的加载进程中,不会将扩大的始末添加到原始的类协会中。runtime对于category的加载进程可以大约的分为上面几步(摘自objc
category的密码
):

  • objc runtime的加载入口是三个叫_objc_init的方法,在library加载前由libSystem dyld调用,进行伊始化操作
  • 调用map_images格局将文件中的image map到内存
  • 调用_read_images办法初阶化map后的image,那其间干了众多的事情,像load具备的类、协议和category,著名的+ load方法就是这一步调用的
    -仔细看category的初阶化,循环调用了_getObjc2CategoryList艺术,这一个方法拿出去看看:
  • .…

那整个的经过爆发在_objc_init函数中,函数完毕如下

 皇冠现金app 5

简简单单的话在load_images函数中最终会走到下边的代码调用来加载所有的类以及类的归类

 皇冠现金app 6

基于地点的代码加上runtime的加载顺序,可以继承推出:

  • @dynamic事实上是将品质的加载推迟到类加载成功后

其余,前边也说过在缺少ivar的场合下不或者自动合成setter/getter,除了category自小编是不被添加到类协会中的,所以不可以运用类社团的ivar合成属性外,还有分类自个儿结构的难点

struct category_t { const char *name; /// 类名 classref_t cls; ///
类指针 struct method_list_t *instanceMethods; /// 实例方法 struct
method_list_t *classMethods; /// 类方法 struct protocol_list_t
*protocols; /// 扩充的协商 struct property_list_t
*instanceProperties; /// 增添属性 method_list_t *methodsForMeta(bool
isMeta) { … } property_list_t *propertiesForMeta(bool isMeta) { …
} };

1
2
3
4
5
6
7
8
9
10
11
struct category_t {
    const char *name;    ///  类名
    classref_t cls;  ///  类指针
    struct method_list_t *instanceMethods;  ///  实例方法
    struct method_list_t *classMethods;  ///  类方法
    struct protocol_list_t *protocols;  ///  扩展的协议
    struct property_list_t *instanceProperties;  ///  扩展属性
 
    method_list_t *methodsForMeta(bool isMeta) { … }
    property_list_t *propertiesForMeta(bool isMeta) { … }
};

可以见到分类布局自己是不设有ivar的容器的,由此缺少了自动合成属性的尺码。末了还有2个标题,大家在行使objc_associate铺天盖地函数绑定属性的时候那几个变量存储在了什么地方?

 皇冠现金app 7

runtime底层,存在一个品类为AssociationHashMap的哈希映射表保存着对象动态增进的性质,各个对象以自家地址为key保安着壹个绑定属性表,我们动态增加的属性就都存储在那些表里。

上一篇:闲话内存管理

1 赞 1 收藏
评论

至于小编:林欣达

皇冠现金app 8

iOS码农一枚
个人主页
·
作者的小说
·
1
·
    

相关文章