Effective Objective-C 2.0笔记

一 熟悉Objective-C

  1. 了解Objective-C语言的起源
  2. 在类的头文件中尽量少引入其他头文件
  • 除非确有必要,否则不要引入头文件。要在某个类的头文件中提及别的类(头文件不涉及被引用类的方法和变量)使用@class。
  1. 多用字面量语法,少用与之等价的方法
  • 应使用字面量语法创建字符串、数值、数组、字典。
    NSNumber *someNumber = @1;
    NSArray *animals = @[@"cat",@"dog",@"mouse",@"badger"];
    NSDictionary *personData = @{@"firstName" : @"Matt",@"lastName" : @"Galloway",@"age" : @28};
  • 应通过取下标操作来访问数组下标或字典中的键所对应的元素。
    NSString *dog = animals[1];
    NSString *lastname = personData[@"lastName"];
  • 用字面量语法创建数组或字典时,若值中有nil则会抛出异常,使字面量语法更为安全。
  1. 多用类型常量,少用#define预处理指令
  • 不要用预处理指令#define定义常量。这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找与替换。即使有人重新定义了常量值,编译器也不产生警告。(#define能定义函数)
    #define ANIMATION_DURATION 0.3

  • 在.m中使用static const来定义“只在编译单元内可见的常量”,常用的命名法是在常量前面加字母k。
    //EOCAnimatedView.m
    #import "EOCAnimatedView.h"
    static const NSTimerInterval kAnimationDuration = 0.3;

  • 在.h中使用extern来声明全局常量,并在相关.m中定义其值。这种常量要出现在全局符号表中,其名称应加以区隔,通常用与之相关的类名做前缀。
    //EOCAnimatedView.h
    extern const NSTimeInterval EOCAnimatedViewAnimationDuration;
    //EOCAnimatedView.m
    const NSTimeInterval EOCAnimatedViewAnimationDuration = 0.3;

      //in the header file
      extern NSString *const EOCStringConstant;
      //in the implementation file
      NSString *const EOCStringConstant = @"VALUE";
    
  1. 用枚举表示状态、选项、状态码

二 对象、消息、运行期

  1. 理解“属性”这一概念
  • 使用@dynamic关键字阻止编译器自动合成存取方法,它会告诉编译器不要自动创建实现属性所用的实例变量,也不要为其创建存取方法。
  • 属性特质
    非对象类型用assign
    属性对象用strong
    控件用weak
    字符串NSStringcopy
  • 开发iOS程序时应使用nonatomic属性,因为atomic属性会严重影响性能。
  1. 在对象内部尽量直接访问实例变量
  • 在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。
  1. 理解“对象等同性”这一概念
    NSString *foo = @"Badger 123";
    NSString *bar = [NSStringWithFormat:@"Badger %i",123];
    BOOL equalA = (foo == bar); //< equalA = NO
    BOOL equalB = [foo isEqual:bar]; //< equalB = YES;
    BOOL equalC = [foo isEqualToString:bar]; //<equalC = YES;
  • == 表示指向同一块内存
    isEqualToString:比调用isEqual:方法快
  1. 以“类族模式”隐藏实现细节
  2. 在既有类中使用关联对象存放自定义数据
  3. 理解objc_msgSend的作用
  4. 理解消息转发机制


    Paste_Image.png
  5. 用“方法调配技术”调试“黑盒方法”
  6. 理解“类对象”的用意
  • isMemberOfClass:能够判断对象是否为某个特定类的实例,而isKindOfClass:能够判断出对象是否为某类或其派生类的实例

三 接口与API设计

  1. 用前缀避免命名空间冲突
  • Apple宣称其保留使用所有“两字母前缀”(two-letter prefix)的权利,所以你自己选用的前缀应该是三个字母。
  1. 提供“全能初始化方法”
  2. 实现description方法
  • 实现description方法返回一个有意义的字符串,用以描述该实例。
    #import <Foundation/Foundation.h>
    @interface EOCPerson : NSObject
    @property (nonatomic,copy,readonly) NSString *firstName;
    @property (nonatomic,copy,readonly) NSString *lastName;
    -(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName;
    @end

       @implementation EOCPerson
       -(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName{
            if ((self = [super init])) {
                _firstName = [firstName copy];
                _lastName = [lastName copy];
            }
       return self;
       }
    

该类的的description方法通常可以这样实现:
-(NSString *)description{
return[NSString stringWithFormat:@"<%@: %p,"%@ %@">",[self class],self,_firstName,_lastName];
}
输出如下格式信息:
EOCPerson person = [[EOCPerson alloc] initWithFirstName:@"Bob" lastName:@"Smith"];
NSLog(@"person = %@",person];
//output
person=<EOCPerson: 0x7fb249c030f0,"Bob Smith">
或者用NSDictionary类的description方法
- (NSString
)description {
return [NSString stringWithFormat:@"<%@: %p, %@>",
[self class],
self,
@{@"title":_title,
@"latitude":@(_latitude),
@"longitude":@(_longitude)}
];
}

  1. 尽量使用不可变对象
  2. 使用清晰而协调的命名方式
  • 方法名和变量名使用“驼峰式大小写命名法”(camel casing)——以小写字母开头,其他单词首字母都大写。类名也用驼峰命名法,不过首字母要大写,且前面通常还有两三个前缀字母。方法名不要使用缩略后的类型名称。
  1. 为私有方法名加前缀
  2. 理解Objective-C错误模型
  3. 理解NSCopying协议

四 协议与分类

  1. 通过委托与数据源协议进行对象间通信
  2. 将类的实现代码分散到便于管理的数个分类之中
  3. 总是为第三方的分类名称加前缀
  4. 勿在分类中声明属性
  5. 使用“class-continuation分类”隐藏实现细节
  6. 通过协议提供匿名对象
  • 具体的对象类型可以淡化成遵从某协议的id类型,协议里规定了对象所应实现的方法。
  • 使用匿名对象来隐藏类型名称(或类名)。

五 内存管理

  1. 理解引用计数
  2. 以ARC简化引用计数
  3. dealloc方法中只释放引用并解除监听
  4. 编写“异常安全代码”时留意内存管理问题
  5. 以弱引用避免保留环
  6. 以“自动释放池”降低内存峰值
  7. 用“僵尸对象”调试内存管理问题
  8. 不要使用retainCount

六 块与GCD

  1. 理解“块”这一概念
  • 块是C、C++、Objective-C中的词法闭包。
  • 块可接受参数,也可返回值
    块类型的语法结构:return_type (^block_name)(parameters)
    下面所定义的块,返回int值,并接受两个int做参数
    int (^addBlock)(int a,int b)=^(int a,int b){
    return a+b;
    };
    int add = addBlock(2,5); //< add=7
    在声明块的范围里的全部变量,都可以为其所捕获,也就是说在块里依然可用。以下代码就使用了块以外的变量:
    int additional = 5;
    int (^addBlock)(int a,int b)=^(int a,int b){
    return a+b+additional;
    };
    int add = addBlock(2,5); //< add=12
    默认情况下,为块所捕获的变量,是不可以在块里修改的。在本例中,假如块内的代码改动了additional变量的值,那么编译器就会报错。不过,声明变量的时候可以加上__block修饰符,就可以在块内修改了。
  1. 为常用的块类型创建typedef
  • 以typedef重新定义块类型,可令块变量用起来更加简单
    typedef int(^EOCSomeBlock)(BOOL flag,int value);
    EOCSomeBlock block = ^(BOOL flag,int value){
    //Implementation
    };
  1. 用handler块降低代码分散程度
  2. 用块引用其所属对象时不要出现保留环
  3. 多用GCD,少用同步锁
  4. 多用GCD,少用performSelector系列方法
  • 延后执行某项任务
    dispatch_time_t time =dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0*NSEC_PER_SEC));
    dispatch_after(time, dispatch_get_main_queue(), ^{
    [self doSomething];
    });
    把任务放在主线程上执行
    dispatch_async(dispatch_get_main_queue(), ^(
    [self doSomething]
    ));
  1. 掌握GCD及操作队列的使用时机
  • 在解决多线程与任务管理问题时,GCD并非唯一方案(NSOperationQueue
  1. 通过Dispatch Group机制,根据系统资源状况来执行任务
  2. 使用dispatch_once来执行只需运行一次的线程安全代码
  3. 不要使用dispatch_get_current_queue

七 系统框架

  1. 熟悉系统框架
  2. 多用块枚举,少用for循环
  • 遍历collection有四种方式,最基本是for循环,其次是NSEnumerator遍历法及快速遍历法(for in),最新最先进的方式则是“块枚举法”
    NSArray
    -(void)enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop)block
    NSDictionary
    -(void)enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL * stop)block
  1. 对自定义其内存管理语义的collection使用无缝桥接
  2. 构建缓存是选用NSCache而非NSDictionary
  3. 精简initialize与load的实现代码
  4. 别忘了NSTimer会保留其目标对象
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容