【笔记】《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》

该书最令我受益匪浅的是OC对象间互动及关系,涉及到的具体实现,填补了一直以来单纯的做开发而不懂具体过程这一空白部分,也看到了要写出优秀的易于扩展的代码,这条路要学习的东西还很多。

  • 为减少编译时间,把只需要类名不需要细节的类写为@class
  • 为简洁,安全(数组插入nil时易于查错):多用字面量快速创建对象 例@1
  • 多用类型常量代替#define:
 例:使用static NSString * const account = @"account" 来代替:
#define XMGAccount @"account" .
注意:不要用预处理定义常量,在.m中使用static const 定义只在实现文件(编译单元内)中可见的常量。

[const,static,extern)的使用在文底,见附1]

  • 读取实例变量采用直接访问,设置实例变量的时候通过属性来做。

  • 理解对象等同性: == 和 isEqual 以及 isEqualToString 的不同

  • 每个OC对象实例都是指向某块内存数据的指针,所以类型后面加‘*’,而id类型本身就是指针。没有*的实例存放在栈区

  • 类对象是单例,可以精确判断对象是否为某类实例的方法为: if ([object class] == [某个类 class]),尽量使用类型信息查询方法(isMemberOfClass对象是否为某个特定类的实例)(isKindOfClass对象是或否为某类或其派生类的实例)来确定对象类型,而不要直接比较类对象,因为某些对象肯盟实现了消息转发功能。

  • 命名:所遇的类都应该加前缀,避免两字母前缀。命名重复报错:duplicate 。解决方法:可加公司,项目等相关前缀。如果要添加分类,要为分类及分类中的方法加上前缀。

  • 尽量把对外公布的属性设为只读,默认属性为可读可写。内部数据可在.h中readOnly,.m中readwrite;为了避免内部写和外部读同时进行,可用dispatch queue等方法将数据读取操作设为同步操作。

  • 开发者要避免单用下划线前缀,因为这种做法是预留给苹果公司用的,也防止无意间覆写父类同名方法,

  • 不要在分类中声明属性

  • 向第三方添加分类时,方法名前加专用的前缀

  • block:

    • 强大之处:在其声明范围内,所有变量都可以在block中使用,默认不可以在block中修改变量,如果添加__block修饰符,就可以改了。
    • block会把所捕获的所有变量都拷贝一份,拷贝的不是对象本身,而是指向对象的指针变量。block内存区域分配在栈中,因此只在定义它的范围内有效。
    • block可以分配在栈上/堆上,也可以是全聚德 ,分配在栈上的可以拷贝到堆里,在堆里就具备引用计数了,block属性用strong修饰。代码存放在堆区时,就需要特别注意,因为堆区不像代码区不变化,堆区是不断变化的(不断创建销毁)。因此代码有可能会被销毁(当没有强指针指向时),如果这时再访问此段代码则会程序崩溃。因此,对于这种情况,我们在定义一个block属性时应指定为strong,或copy
  • GCD不能指定操作优先级,依赖关系。GCD属于派发队列,NSOperation属于操作队列,通知(NSNotificationCenter)也属于操作队列。

  • Foundation框架中的类,前缀都是NS,CoreFoundation对象不归ARC管理,开发者需要自己在合适时间调用CFRetain/CFRelease.

  • 遍历最新最先进的方法是“块枚举法”,其本身就能通过GCD来并发执行遍历操作,无需另行编写代码。

  • ratain是个函数指针,其所指向的函数接受两个参数,内存分配器及即将加入的最终值。

  • load:加入运行期系统的类/分类,仅调用一次,先调用类再调用分类的,执行子类load方法前,先执行完所有超类load方法,若代码还依赖其他程序库,也先执行其他相关类load方法。

    • initialize在首次使用该类时调用,仅调用一次。
    • initialize:不会阻塞,且是在“线程安全的环境”执行,如果某个类未实现,而超类实现了,那么会运行超类实现代码。
      load不遵从继承,无法判断载入顺序,因此不安全。

看别人的笔记点这里

附1:

一、const与宏的区别:

const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量。
编译时刻:宏是预编译(编译之前处理),const是编译阶段。
编译检查:宏不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。

  • 宏的好处:宏能定义一些函数,方法。 const不能。
  • 宏的坏处:使用大量宏,容易造成编译时间久,每次都需要重新替换。

二、const作用:限制类型 //修饰的常量应该从右往左读

1.const仅仅用来修饰右边的变量(基本数据变量p,指针变量*p)
2.被const修饰的变量是只读的。

 const int b = 20; 等同于 int const b = 20; 

三、static和extern

static作用:(修饰局部变量/全局变量)
修饰局部变量:
1.延长局部变量的生命周期,程序结束才会销毁。
2.局部变量只会生成一份内存,只会初始化一次。
3.改变局部变量的作用域。
修饰全局变量
1.只能在本文件中访问,修改全局变量的作用域,生命周期不会改
2.避免重复定义全局变量

extern作用:(只读)
只是用来获取全局变量(包括全局静态变量)的值,不能用于定义变量
extern工作原理:
先在当前文件查找有没有全局变量,没有找到,才会去其他文件查找。

// 全局变量:只有一份内存,所有文件共享,与extern联合使用。 
int a = 20; 

// static修饰全局变量 
static int age = 20; 

- (void)test { 
    // static修饰局部变量 
    static int age = 0; 
    age++; 
    NSLog(@"%d",age); 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self test]; 
    extern int age;
    NSLog(@"%d",age); 
} 

四、static与const联合使用(声明一个只读的静态变量,变量一定要用static和const来声明)

static与const作用:声明一个只读的静态变量,实际上相当于宏
开发使用场景:在一个文件中经常使用的字符串常量,可以使用static与const组合

// 开发中常用static修饰全局变量,只改变作用域 ,为什么要改变全局变量作用域,防止重复声明全局变量。
// 开发中声明的全局变量,有些不希望外界改动,只允许读取。比如一个基本数据类型不希望别人改动

// 声明一个静态的全局只读常量

static const int a = 20; 
  • static和const联合的作用:声明一个静态的全局只读常量
  • iOS中staic和const常用使用场景,是用来代替宏,把一个经常使用的字符串常量,定义成静态全局只读变量.

// 开发中经常拿到key修改值,因此用const修饰key,表示key只读,不允许修改。

static NSString * const key = @"name"; 

五、extern与const联合使用 (在多个文件中经常使用的同一个字符串常量)

开发中使用场景:在多个文件中经常使用的同一个字符串常量,可以使用extern与const组合。
原因:
static与const组合:在每个文件都需要定义一份静态全局变量。
extern与const组合:只需要定义一份全局变量,多个文件共享。

例:通知

.h 中: extern NSString *const HOMEREFRESHNOTIFICATION
.m中:   NSString *const HOMEREFRESH = @“homerefreshnotification”;

你可能感兴趣的:(iOS)