Effective Objective-C 2.0笔记

作者: gamper | 来源:发表于2016-05-30 11:29 被阅读85次

    一 熟悉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会保留其目标对象

    相关文章

      网友评论

        本文标题:Effective Objective-C 2.0笔记

        本文链接:https://www.haomeiwen.com/subject/arqtdttx.html