第一次读这本书是在刚刚接触iOS开发的时候,那时的我没有一点开发经验,书中的很多内容都只是一知半解,甚至有所忽略。半年多的时间过去了,有些许开发经验的我再来读这本书,又有了很多收获,因此便有了这篇“再读”笔记。
第六章源文件组织
- 一个文件在接口部分存放的代码包括
- 类的@interface指令:声明继承关系
- 公共struct定义
- enum常量
- define定义
- extern全局变量
第八章Foundation Kit介绍
- NSArray只能存储OC对象,不能存储
- C语言的基础数据类型,如int,float,enum,struct
- OC的基础数据类型,如NSInteger,NSUInteger,CGFloat
- nil
- 可以通过NSNumber类将OC的基础数据类型转化为对象存储在NSArray中,简易的写法为@()。
- NSArray可以通过字面量语法创建,并且在结尾处不用补上nil。但是作为NSArray子类的NSMutableArray却没有字面量语法来创建起对象。
- 判断数组内是否包含某一对象有两种常用方法:
- (BOOL)containsObject:(ObjectType)anObject ;
-
- (NSUInteger)indexOfObject:(ObjectType)anObject ; //若返回值为NSNotFound,则说明不包含该对象
上述两个方法都是建立在对象的-(BOOL)isEqual:
方法之上的。
- 当要读取的key值在NSDictionary对象中不存在时会返回nil。
第十章对象初始化
- BOOL类型变量初始化为NO;int类型变量初始化为0;float类型变量初始化为0.0;指针对象初始化为nil。
- 如果创建了一个指定初始化函数,则一定要在该初始化函数中调用超类的指定初始化函数。
- 如果初始化函数不止一个,则需要选择一个作为指定初始化函数。被选定的方法应该调用超类的指定初始化函数,其它初始化函数按照该指定初始化函数的形式来实现。
第十一章属性
- 属性的默认特性为(atomic, assign, readwrite)。
- 当属性为只读时,编译器只会自动生成getter方法,而不会自动生成setter方法。此时如果不定义setter方法,就无法通过点语法进行赋值,可以通过以下代码解决该问题。
#import <Foundation/Foundation.h>
@interface BaseClass : NSObject
@property (nonatomic, copy,readonly) NSString *name ;
- (void)setName:(NSString *)name ;
@end
#import "BaseClass.h"
@implementation BaseClass
@synthesize name=_name ;
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release] ;
_name = [name copy] ;
}
}
@end
- 如果同时重写了属性的setter方法和getter方法,那么编译器将不会将属性的名称与支持属性的实例变量名相关联,此时需添加代码
@synthesize name=_name ;
。
第十二章类别
- 类别的局限性
- 无法向类中添加新的实例变量
- 当方法名称发生冲突时,类别具有更高的优先级
- 类别的优势
- 将类的实现代码分散到多个不同文件或框架中
- 创建对私有方法的前向引用:只要知道对象支持的某个方法的名称,即使该对象所在类的接口中并没有声明该方法也可以调用。不过这么做编译器会报错,但是可以通过新建一个该类的类别并且在该类别的.h文件中声明原始类的该私有方法来解决该问题
- 创建一个NSObject的类别来向对象添加非正式协议
- 类扩展
- 不需要名字
- 在包含源代码的类中使用它
- 添加实例变量
- 可以将只读权限改为可读写权限
- 创建数量不限
第十四章代码块和并发性
使用block进行回调时要注意循环引用问题:如果A创建并引用了B,B引用了callBackBlock,而callBackBlock中又引用了A,就会形成循环引用。解决方法是使用弱引用来解除这个循环:
__weak A *weakSelf = self
连续队列
- 当一连串的任务需要按照一定的顺序执行时可以使用连续队列
- 任务执行顺序为先入先出
- 可创建任意数量的连续队列,它们并行操作任务
- 串行执行后台任务,主要用于处理耗时比较长的方法,譬如下载,安装,删除等
- 代码示例
dispatch_queue_t serialQueue = dispatch_queue_create("com.apress.mySerialQueue", nil) ;
并发队列
- 适用于那些可以并行运行的任务
- 遵从先入先出的规范,且任务可以在前一个任务结束前就开始执行
- 系统提供了四种全局队列,这些队列仅仅通过优先级加以区别。因为存在队列的优先级,所以那些在高优先级队列中的任务会比在默认或低优先级队列中的任务先执行,而默认级别队列的优先级又高于低优先级队列。被设置成后台级别的队列,它会等待所有比它级别高的队列中的任务执行完或CPU空闲的时候才会执行自己的任务
- 后台执行非UI操作
- 代码示例
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
dispatch_queue_t concurrentQueue = dispatch_queue_create(“com.appress.myConcurrentQueue”,DISPATCH_QUEUE_CONCURRENT) ;
主队列
- 执行的是应用程序的主线程任务
- 使用
dispatch_get_main_queue()
可以访问与应用程序主线程相关的连续队列 - 在一个并发队列上完成任务后更新UI的一般选择,譬如页面push,pull
添加任务
- 同步:同步添加任务到队列后,被添加的任务会阻塞当前线程,直到这些任务执行完
- 异步:异步添加任务到队列中后会立即返回,不必等待任务完成。任务会在之后由GCD决定执行
- 通过代码块添加任务:异步添加
dispatch_async
,同步添加dispatch_sync
第十七章文件加载与保存
- 采用NSCoding协议的对象通过实现
-encodeWithCoder:
和-initWithCoder:
这两个方法来实现序列化与反序列化,完成与NSData之间的转换。 -
-initWithCoder:
和其他init
方法一样,在为对象执行操作之前,需要使用超类进行初始化。可以采用两种方式,具体取决于父类。如果父类采用了NSCoding协议,则应该调用[super initWithCoder:decoder]
,否则只需要调用[super init]
。
第十八章键/值编码
- 可以通过
-valueForKey:
和-setValue:forKey:
两个方法设置和访问对象的属性。 -
-valueForKey
方法会首先查找以参数命名(格式为-key或-isKey)的getter
方法,如果没有这样的getter
方法将会在对象内寻找名称格式为_key或key的实例变量。 -
-setValueForKey
方法会自动将标量值从相应的对象中取出:
[car setValue:[NSNumber numberWithFloat:2000.0] forKey:@“weight”] ; //属性weight类型为float
-
-valueForKey
方法会自动将标量值(int、float和struct
)放入NSNumber
和NSValue
中:
[car valueForKey:@“modelYear”] ;//属性modelYEar类型为int
- 批处理
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys ;
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues ;
-
<null>
是一种[NSNull null]
对象,而(null)
是一个真正的nil
值。
第二十章NSPredicate
- 创建谓词:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@“SELF….”, string] ;
- 计算谓词:
BOOL match = [predicate evaluateWithObject:object] ;
- 过滤数组内容:
- (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate ;