runtime-分类为何不生成setter和getter

前言

前方几乎天有人提问我一个题材:为什么分类不克自动创建get
set方法。老实说,笔者从不曾错过思想过这题材。于是这次通过代码实践以及runtime源码来探讨这个问题。

同作用

  • 供丰富的简单大方好看的主题,同时支持于定义
  • 提供丰富的渲染 Markdown 之后的 CSS 样式,同时支持自定义样式
  • 英文单词的全自动补全效,按下 Esc 键列出补全的列表
  • 字符、单词统计功能
  • 支持 fenced code blocks
  • TeX 数学公式的支持
  • 支持导出 HTML 和 PDF 两种格式
  • 便民的快捷键操作

从今源码解析

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,顾名思义存放的是变量的职务属性,与的相应的还有一个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洋洋洒洒函数绑定属性之时光这些变量存储在了何?

总结

OK,总结了了,如果未是 Mou 在自的 Mac
上发卡顿,我为未尝想在只要转移一悠悠编辑器,目前自当就此 MacDown
感觉还是充分不利的,因为起代码高亮支持即得将自身养了。至于你选哪一样暂缓,你可以下载下来自己经验感受,反正软件还非常有些。也许你同自家同样,因为有小缺点放弃某个软件,又因为某小作用的喜怒哀乐而喜上某软件。

好像的属性

  • 常规创建类
    @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的公式:

Mou 和
MacDown
是自身以 Mac 下用过的星星缓缓可以之 Markdown 编辑器。之前一直采取的凡
Mou,但不知怎的近年 Mou 在保留时到底有 4s
以上的卡顿,这让自己好无爽,没找到中之化解方法,于是自己被迫去摸索另外的
MD 编辑器。我尝试过十分多种,但到底认为没有 Mou 体验好,最终让自家找到了
MacDown——OS X下开放源代码 Markdown 编辑器。

未雨绸缪干活

为能够压缩输出类数据的代码工作,笔者根据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是的多寡存储到三独数组中,用来清除父类的数据输出

GFM Task List 支持

MacDown 支持 Task
list,有矣这个功能,你可拿公的
MD 编辑器立马变成 TODO list,是休是充分赞赏?

MacDown 对 Task list 的支持

分类属性

  • 分类中上加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失败

MacDown 特色

总结

第一,iOS的归类在runtime贯彻之结构体中连无存Ivar种类的容器,缺少了自动合成setter以及getter的必要条件,因此当分拣中宣称的属性默认为@dynamic修饰。

辅助,OC本身是同一山头原型语言,对象以及类原型很像。类对象执行alloc方就是像是原型模式遭遇的copy操作一样,类保存了copy所待的实例信息,这些信内存信息以runtime加载时即便给一定了,没有扩大Ivar的条件。(感谢大表哥的科普)

最后,在runtime遭有一个品类为AssociationHashMap的哈希映射表保存着对象动态增长的性能,每个对象为自家地址也key保护在一个绑定属性表,我们动态增长的特性就还存储在斯表里,这吗是动态增长property能够不负众望的底蕴。

上一篇:闲谈内存管理

转载请注明原文地址和作者

集成 Tumblr 和 Scriptogr.am 发布博文

足配备 Tumblr 和 Scriptogr.am 的信箱,在 Mou 上勾文章通过
File->Post-> 可以颁发暨就有限只平台及,非常便于。

Mou 支持集成 Tumblr 和 Scriptor.am

私下的故事

颇有趣味关注了立即有限舒缓软件的作者及私下的故事,发现大有趣,在测评两迟迟软件前我们先行八平八故事吧。

Mou
的作者罗晨,个人主页:http://chenluois.com/,现居住天津,自由职业者。MacDown
的作者Tzu-ping
Chung,个人主页:https://uranusjr.com/,现住台北市,应该是台湾同胞吧。

根据 MacDown
作者的介绍,他就一度是
Markdown 的重度用户,而用的编辑器基本是 Mou,但 Mou 可以拍卖fenced
code
blocks,却对代码高亮不支持,同时在渲染
Markdown 时也产生 bug,这让他煞是烦。Mou
的撰稿人就正准备转手该软件,一直尚未创新,所以,他就是起从头开始模仿
Mou 写一个,因为是 Markdown editor for Macs,所以取名为 MacDown。

MacDown 作者 Chung 在征得 Mou 作者 Luo 的许以了 Mou
的几乎款主题,发布了 MacDown 的原来版本。Luo 最后发现 MacDown
时,很气愤,并指责 Chung 是 copycat,意思是 MacDown 山寨了 Mou。Chung
也发现及实在是团结抄袭了 Mou
很多事物,根据某条推文的建议(并不是Luo发布的),将之前
github
中色描述
改成了:

MacDown is an open source Markdown editor for OS X, released under the
MIT License. The author stole the idea from Chen Luo’s Mou so that
people can make crappy clones.
^1

比详细的始末可瞻仰 Chung
的博客。至于
MacDown 和 Mou 的涉嫌是什么样的,是免是 MacDown 就是不道德地克隆了 Mou
呢?这个每个人都有投机的见地,这里虽未讨论了。

喜悦之是,目前少于迟迟软件还找到好的上进模式,Mou 已经做到了众筹,即将揭晓
1.0 版本,如果发生对 Mou
有情绪的同班可以支持作者;MacDown
依旧会活动自己开源之征程。

Chung 的如出一辙句子话也道有了自的心声:

Let’s focus on making better software for everyone.

吓了,八卦完了,最后我要指向片号作者表示真诚的谢忱,贡献给咱好用的软件!下面我会根据自己感受,分别领到一下个别磨蹭软件各自的特征地方。

语言支持

Mou 内置 CJK
字符支持,你可以非常易使中文、日文、韩文等来形容稿子,同时还支持竖排的作风。

Mou 支持 CJK 及竖排

代码高亮

Mou 和 MacDown 都支持 fenced code
blocks(前后三独反引号可以象征代码块),但 MacDown
支持加语言标识符实现代码高亮,这对准程序员来说简直是福音啊,非常强的功用。

MacDown 支持代码高亮

Jekyll Front-matter 支持

过剩总人口利用 Jekyll 作为博客引擎,这时 Jekyll
的前面那段该怎么去渲染呢?MacDown 和 github 一样可支持。

MacDown 对 Jekyll front-matter 的支持

Mou 特色效益

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图