Objective-C Runtime (一)

computer-1245714_1920.jpg

讲述背景

平时在网络上和工作中,与各个工种的开发人员进行交流的时候,我发现过一个问题,很多人对面对对象的一些基础概念含糊不清,甚至一无所知。

具体到iOS开发界,常见的开发人员也只是在盲目的堆砌业务功能,而不去考虑这些代码在基础层面的含义。当然基础具体到哪一层次,我只能尽力。

我的观点是,人与人的讨论是需要有某些双方一致认同的基础的,否则,最后也难以得出一个一致认同的结果,自说自话毫无意义。

所以我觉得需要把很多概念弄清楚,不要混用。


讲解runtime所需的前置知识

Objective-C 是一门动态语言

动态语言是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。C、C++等语言则不属于动态语言。Objective-C 的动态特性是由其Runtime环境来实现的

动态性的表现

C++里类别与方法的关系严格清楚,一个方法必定属于一个类别,而且在编译时(compile time)就已经紧密绑定,不可能调用一个不存在类别里的方法。

在Objective-C,类别与消息的关系比较松散,调用方法视为对对象发送消息,所有方法都被视为对消息的回应。

所有消息处理直到运行时(runtime)才会动态决定,并交由类别自行决定如何处理收到的消息。

也就是说,一个类别不保证一定会回应收到的消息,如果类别收到了一个无法处理的消息,程序只会抛出异常,不会出错或崩溃。

对runtime 前置说明

  • Runtime的版本有很多
  • 早期的runtime版本不能原生地支持对某个类新增变量
  • Mac OS X 10.6 之后的Runtime被称为modern runtime
  • modern runtime实现了原生支持动态增加属性,使用到了称之为Associated References的技术,本文讲述的是 modern runtime的相关知识

前面的两篇文章讲到了Objective-C类的结构,现在将对结构展开讲述其内部,会首先讲到平时开发中常用的实例、类的常用方法,然后再深入到runtime层面去理解这些方法。

所以,接下来会讲 Objective-C基本代码的常见表达,然后再去深入到runtime层面去理解你平时常写的这些代码。

当然常用的代码的讨论需要建立一些基础的概念,后面会一一提到。


实例变量和属性的关系

实例变量instance variables,也就是常见的ivars,是对类创建的时候用以描述其实例的组成中的数据的封装。是面对对象的基础概念之一。

  • 每一个类某一个实例变量是唯一的,不能重复

  • 实例变量只有类和其子类的实例可以访问

  • 属性和实力变量并没有唯一确定的关系,属性算是一种访问类的内部信息的一个接口
    属性可以关联到实例变量,用来访问类内部的实例变量

  • 默认情况下,编译器会为你定义的每一个属性自动生成一个实例变量和配套的setter、getter方法。

实例变量的细节

前面的两篇文章已经讲述过,Objective-C的对象,类,类对象,元类都是由结构体实现的

拿C语言进行举例,前面提到过C语言结构体成员的两种访问方式,其实还有另外一种方式,就是得到结构体变量在内存中的首地址,根据每个成员的长度根据偏移量来访问其任何一个成员变量。

事实上这种方式对C语言系的编程语言都是通用的。

但是Objective-C 融和 runtime 使用一些巧妙的办法,使得程序再运行期间去确定偏移量,这就是动态性的表现之一。

再看一看 OC2.0以前 的实例变量的写法

#import <Foundation/Foundation.h>

@interface MTTStudent : NSObject {
    @public
    NSString *_name;
    NSUInteger _age;
    CGFloat _height;
}

@end

采用这种方式使得MTTStudent的某个实例的内存布局在编译时期就已经固定了,碰到要访问_name变量的代码,编译器就会把访问代码转换会偏移量,表示该变量距离MTTStudent的实例的存储地址有多远,通过操作指针中地址来访问这块存储了_name的内存。

这个偏移量是一个硬编码,编译时候用某种长度的整数记录下来。

可是,如果你要插入了一个新的实例变量

#import <Foundation/Foundation.h>

@interface MTTStudent : NSObject {
    @public
    NSDate *_birthDay;//新增一个实例变量
    NSString *_name;
    NSUInteger _age;
    CGFloat _height;

}

@end

新增并插入的的实例变量_birthDay,如以上代码所示,这个如果继续是访问_name的时候使用原来的偏移量将得到错误的地址,重新编译才能获得新的内存布局,使用心得偏移量

Objective-C的做法是,把实例变量当作 一种存储偏移量的“特殊变量”,由类对象来保存,可以调用runtime的借口获取到具体的偏移量。简单来讲就是在运行时分配内存确定偏移量,并且这个偏移量和实例变量绑定起来,后面讲runtime的接口会看到。

偏移量会在运行期查找,如果类的定义变了,那么存储的偏移量也会变,能保证无论何时访问实例变量,都能使用正确的偏移量。

属性的细节

你需要时刻记住面对对象的特性之一:封装,实例变量是对数据的封装,属性是对实例变量的封装,每一层的封装都隐藏了一些融合的细节在其下一层。

属性最终是采用实例变量来实现的,可以把属性理解为一种简称:编译器会自动写出一套存取方法用以访问类中的实例变量。

  • 在类的实现代码中使用@synthesize关键字来指定实例变量的名字

  • 在类的实现代码中使用@dynamic关键字来告诉编译器不要自动生成setter和getter方法,有时候你想使用懒加载 改写属性的setter和getter方法是IDE会提示你有错误,只能重写两者之一,可以同过@dynamic关键字来解决这一问题

属性的特质

所谓属性的特质,是指对属性设置某些修饰,这样编译器在自动实例变量和其存取方法时会考虑这些修饰来生成

属性的特质分为四类:原子性、读写控制、内存管理、方法名

以下的例子是一个具备四类修饰的属性的声明

@property (nonatomic,readwrite,strong,setter=setName:)NSString * name;
  • 原子性,缺省为atomic,iOS平台上的代码一般都要指定nonatomic来提升性能

  • 读写权限,缺省为readwrite,编译器会自动生成读写方法,指定readonly时要配合@synthesize编译器才会生成getter方法。

  • 内存管理语义,有五种 assignstrongweakunsafe_unretainedcopy

  • 方法名字,getter=<name>,setter=<name>


关于内存管理语义的细节后面会专门开文章写一写,这些修饰关系到指针的操作,使用不当会导致很多莫名其妙的bug


参考:

  • 《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》
  • 维基百科

题图来自pixabay.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容