-
BOOL
的实际类型是signed char
,所以赋值给BOOL
类型时,可能会出现截断的情况。 -
#define
指令把YES
定义为1,NO
定义为0。所以不要将BOOL
类型直接和YES
或者NO
进行比较。 - 使用
NSLog
输出对象时,会调用对象的description
方法。所以通过重载NSObject
的description
方法,可以自定义打印对象的内容。若想在调试时,用LLDB的po
命令输出更详细的信息,可以实现debugDescription
。在NSObject
的默认实现中,它只是简单调用了description
方法。 -
NSValue
类型可以存储任意值。通过将结构体、枚举值转化为NSValue
,就可以存放到数组和字典中。
转化:
NSRect rect = NSRectMake(1, 2, 3, 4);
NSValue *value = NSValue valueWithBytes:&rect objCType:@encode(NSRect);
[array addObject:value];
提取:
value = [array objectAtIndex:0];
[value getValue:&rect]; - 事件循环:一个典型的图形应用程序往往花费许多时间等待用户操作。在控制程序运行的人慢腾腾地作出决定(比如点击鼠标或按下某个键)以前,程序将一直处于空闲状态。当发生这样的事件时,程序将被唤醒并开始工作,执行必要的操作以响应这一事件。在处理完这事件后,程序返回到休眠状态并等待下一个事件发生。为了降低程序的内存空间占用,
cocoa
会在程序开始处理事件之前创建一个自动释放池,并在事件处理结束后销毁。这样可以尽量减少累 积的临时对象的数量。 - 自动释放池被清理的时间是完全确定的。要么是在代码中,自己手动销毁,要么是使用
AppKit
时,在事件循环结束时销毁。 - 使用ARC进行内存管理时,不能简单的将可保留对象指针(ROP)表示成不可保留对象指针(non-ROP)。因为ARC无法对不可保留对象进行内存管理,所以需要明确所有权问题和对不可保留对象手动进行内存管理。
桥接转换可以明确所有权的问题,包括三个关键字:
__bridge
、__bridge_retained
和__bridge_transfer
-
__bridge
:转换会传递指针但不会传递所有权。 -
__bridge_retained
:所有权会转移到不可保留对象指针上。 -
__bridge_transfer
:所有权会转移到可保留对象指针。
- 结构体和集合体中不能使用ROP作为成员,可以通过
void *
和桥接转换来解决这个问题. - 非正式协议(声明
NSObject
的类别):
@interface NSObject(NetWorkDeal)
- (void)networkFail; - 自定义类实现了
NSCopy
协议,则需要实现copyWithZone
方法,如下
- (id)copyWithZone:(NSZone *)zone{
TestClass *test;
test = [[[self class] allocWithZone:zone] init];
return test;
} - 代码块声明:
void (^ myBlock)(int i);
代码块定义:
myBlock = ^(int i){
return i;
}
typedef 使用:
typedef void (^ MyBlock)(int i);
MyBlock myBlock = ^(int i){
return i;
}
代码块定义时,会复制并保存本地变量(非静态、未加
__block
修饰)的状态。
- GCD队列相关操作:
-
dispatch_retain
和dispatch_release
可以用自定义的队列进行内存管理。 -
dispatch_suspend
和dispatch_resume
可以暂停队列和重新启动队列。 -
dispatch_queue_create
生成的Dispatch Queue都使用与默认优先级Global Dispatch Queue相同执行优先级的线程。可以通过dispatch_set_target_queue
变更Dispatch Queue的执行优先级。这个方法同时还会设定Dispatch Queue的执行阶层。例如,将多个Serial Dispatch Queue通过dispatch_set_target_queue
指定目标到同一个Serial Dispatch Queue。那么原本会并行执行的多个Serial Dispatch Queue,在目标Serial Dispatch Queue上,只能同时执行一个处理。 -
dispatch_set_context
和dispatch_get_context
可以为队列指派上下文。
设置:
NSMutableArray *myContext = [[NSMutableArray alloc] init];
[myContext addObject:@1];
dispatch_queue_t serialQueue = dispatch_queue_create("com.appress.myQueue", DISPATCH_QUEUE_SERIAL);
dispatch_set_context:(serialQueue, (__bridge_retained void *)myContext);
获取:
NSMutableArray *myContext = (__bridge NSMutableArray *)dispatch_get_context (dispatch_get_current_queue());
说明:上下文对象的内存需要手动管理,所以在弃用队列时,调用下面的函数(ARC下),释放上下文
void finalizerFunction:(void *context){
NSMutableArray myContext = (__bridge_transfer NSMutableArray)context;
[myContext removeAllObject];
}
-
NSPropertyListSerialization
可以为存储和加载属性列表提供便利:
存储:
NSString *error = nil;
NSData *data = [NSPropertyListSerialization dataFromPropertyList:nameArray format:NSPropertyListBinaryFormat_v1_0 errorDescrioption:&error];
[data writeToFile:@"/tmp/name.txt"];`
加载:
NSPropertyListFormat propertyListFormat = NSPropertyListXMLFormat_v1_0 ;
NSString *error = nil;
NSMutableArray *nameArray = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&propertyListFormat errorDescription:&error]; - 对象的序列化和反序列化,需要类实现NSCoding协议。NSKeyedArchiver和NSKeyedUnarchiver可以对对象进行序列化和反序列化。
序列化:
NSData *data = [NSKeyedArchiver archiveDataWithRootObject:object];
反序列化:
[NSKeyedUnarchiver unarchiveObjectWithData:data]; -
Foundation
框架定义了两个和枚举有关的宏:
-
NS_ENUM
:可以根据编译器支持情况决定是使用新式的语法还是老式语法。 -
NS_OPTIONS
:若编译方式为不按C++编译,则展开和NS_ENUM
相同。若按C++编译,则展开的代码略有不同。这么处理的主要原因是,在C++编译的模式下,进行按位或运算时,会认为运算结果的数据类型应该是枚举的底层数据类型,而且不允许将这个底层类型“隐式转换”为枚举类型。若展开的代码和NS_ENUM
一样,就会报错。
根据上面的描述,在需要进行按位运算时,采用
NS_OPTIONS
,其它情况可以使用NS_ENUM
。