2.对象、消息、运行期

第6条 理解属性这一概念


以上也是Category 为何不能添加成员变量的原因,更多参考:
http://quotation.github.io/objc/2015/05/21/objc-runtime-ivar-access.html
http://www.jianshu.com/p/2d63477c4d46

  • __unsafe_unretained 跟 assign 类似,只不过它是修饰对象的,而 assign 是修饰基本类型的。两者修饰的属性在释放时,都不会自动将属性值置为 nil。

  • 修饰NSString 的时候最好用 copy,原因如下:

@property (retain) NSString *name;
- (void)xxx
{
    NSMutableString *mName = [@"mName" mutableCopy];
    self.name = mName;
    //接下来,如果我修改了 mName(比如在 mName上拼字符串),那么self.name也会跟着修改,
    //但开发者可能会认为 self.name 只是个 NSString 的不可变字符串,不应该被修改,但其实却是个 NSMutableString。
    //若用了copy就不会发生这种情况。
}

  • 如果属性用 copy 修饰了,在 init 方法里要对应的用 copy 赋值,如:
@property (copy) NSString *name;

- (instancetype)initWithName:(NSString *)newName
{
    self = [super init];
    if (self) {
        _name = [newName copy]; //要用copy赋值
    }
    return self;
}

  • 如果设置了 readonly ,可以只在 init 方法里赋值(如下代码),其他地方再调用 self.name = xxx 赋值的话,就会报错了。
@property (copy, readonly) NSString *name;

- (instancetype)initWithName:(NSString *)newName
{
    self = [super init];
    if (self) {
        _name = [newName copy];
    }
    return self;
}
  • atomic 和 nonatomic 的区别


第7条 在对象内部尽量直接访问成员变量

  • 在对象内部,读取的时候尽量用成员变量(惰性初始化除外,如下代码),赋值的时候尽量用属性。
    原因:
    1. 读取时,直接访问成员变量,速度会比较快,
    2. 但是如果赋值时,如果直接访问成员变量就绕过了内存管理机制,比如 copy 修饰了一个属性,若直接给成员变量赋值,就会 retain 而不会 copy 了。
    3. 直接访问成员变量,不会触发 KVO。
    4. 用属性,方便在 setter 方法里打断点调试。
  • 在 init 和 dealloc 中,尽量直接使用成员变量读写数据。
// 惰性初始化
- (Student *)student 
{
    if (!_ student) {
        _ student = [Student new];
    }
    return _ student;
}

第8条 理解“对象等同性”这个概念

NSObject 的判断俩对象是否相同的方法 isEqual:- (NSUInteger)hash 的关系:
若用 isEqual: 判断俩对象相等,则 hash 一定相同,但 hash 相同,isEqual: 判断不一定相等。

  • hash函数如何编写(未读懂)
  • NSArray 调用 isEqual: 的实现原理: 先判断个数是否相同,若相同,每一项调用isEqual:判断是否相同。
  • NSSet (集合)是一种哈希表,运用散列算法,查找集合中的元素比数组速度更快,但是它没有顺序。集合中的数据是唯一的,比如我存入俩相同的字符串,集合里只会有一个。

第9条 以“类族(类簇)模式”隐藏实现细节

类族一般没有 init 方法,只有一些工厂方法,它只是一个抽象的基类,中间的实现过程都隐藏了。例如UIButton,初始化没有init,而是用 buttonWithType:,其内部可能是每个类型声明了一个新的类(只是举个UIButton的例子,UIButton实际并不是类族)。
collection类(集合类)一般都是类族,包括 NSArray、NSSet和NSDictionary等,NSString、NSNumber等也是类族,以下结果返回的是NO:

NSArray *arr = [NSArray arrayWithObjects:@"abc", nil];
  if ([arr isMemberOfClass:[NSArray class]])
  {
      NSLog(@"YES");
  }
  else {
      NSLog(@"NO");
  }

第10条 在既有类中使用关联对象存储自定义数据

#import <objc/runtime.h>

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /** 和 assgin 等效 */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /** strong、nonatomic */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /** copy、nonatomic */
    OBJC_ASSOCIATION_RETAIN = 01401,       /** strong、atomic */
    OBJC_ASSOCIATION_COPY = 01403          /**< copy、atomic */
};

//设置关联
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) 

//获取关联的对象值
id objc_getAssociatedObject(id object, const void *key)

//移除指定对象的全部关联对象
void objc_removeAssociatedObjects(id object)  

UIAlertView 的 delegate 传值的时候,如果传一个 tag 还好说,如果是传多个参数,要么用一个子类继承于 UIAlertView,设置多个属性,要么就用关联对象。

第11条 理解 objc_msgSend的作用

C语言是静态绑定,若不考虑内联(inline),当你调用一个函数的时候,编译的时候编译器就知道存在这个函数了。

// OC 中的语句
id retureValue = [obj messageName:parameter];

// 转成C语言后的原型
id retureValue = objc_msgSend(obj, @selector(messageName:), parameter);

objc_msgSend 方法会在 接收者(obj)中寻找方法列表,如果找不到,就在从父类依次往上找,一直找到NSObject,如果还没找到,就开始消息转发。这个过程中,objc_msgSend并非每次都会查找,每个类会有一个缓存,这样大大提高了查找效率。

objc_msgSend_stret
objc_msgSend_fpret
objc_msgSendSuper
...
还有些内容太抽象,此处省略。

第12条 理解消息转发机制

上条介绍的消息传递,传递过程中找不到对应的方法,就会执行消息转发。消息转发分为两大阶段:

  1. 动态解析:询问接收者所属的类,能否动态添加方法。
  2. 完整的消息转发:系统请求接收者用其他方式处理消息。又分为俩阶段(就是俩回调方法),首先,先看下其他类能否处理该消息,若没有,系统会把与消息有关的全部细节封装给NSInvocation对象中,再给接收者,最后一次机会。

代码示例,建了一个EOCAutoDictionary的类,可以用该类任意存值。如:

    ECOAutoDictionary *a = [ECOAutoDictionary new];
    a.data = [NSDate date];
    NSLog(@"a.data-------%@", a.date);

第13条 用“方法调配技术”调试“黑盒方法”

method swizzling,一般用于打印一个系统方法日志,最好不要滥用,否则会让代码不易被读懂。

第14条 理解“类对象”的用意

NSObject 类在 oc 中的定义是:

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}
typedef struct objc_class *Class;
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

举个例子:

NSString *str = @"abc";

看下面的图的定义,在这个例子中,str 的 isa 指针是指向 NSString,而 NSString 也有个 isa 指针,这个指针指向的类就是 元类,说明 NSString 是该元类的一个实例对象。NSString 的类方法就是在元类里定义的。


NSProxy 简单用法:http://ios.jobbole.com/87856/
NSProxy 的作用:负责将消息转发到真正的target的代理类。举个例子,你想要卖一件二手物品,但是你并不想直接跟卖家接触(直接向target发消息),这时你去找了一个第三方,你告诉这个第三方你要买什么、出多少钱买、什么时候要等(向代理发消息),第三方再去跟卖家接触并把这些信息转告卖家(转发消息给真实的target),最后通过第三方去完成这个交易。

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

推荐阅读更多精彩内容

  • Objective-C作为面向对象编程,“对象”(object)就是“基本构造单元”(building block...
    Mark_Lin阅读 319评论 0 1
  • 6.理解“属性”这一概念 @dynamic关键字:告诉编译器不要自动创建实现属性所用的实例变量,也不要为其创建存取...
    Code_Ninja阅读 702评论 0 3
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,670评论 0 9
  • 三月阳光暖人身, 林荫喜鹊喳喳鸣。 桃花渐随夜雨去, 绿叶枝头笑春风。
    天马酒仙阅读 357评论 0 0
  • My code: My test result: 这道题目还是和前面的差不多。然后就是要用while循环把重复的数...
    Richardo92阅读 237评论 0 1