1. #import
和@class
- 除非的确有必要,否则不要引入头文件。一般来说,应该在某个类的头文件中使用向前声明来声明别的类,并在实现文件中引入该类的头文件。这样做可以尽量降低类之间的耦合(coupling)。
- 有时无法使用向前声明,比如要声明某个类遵循一项协议。这种情况下,尽量把“该类遵循某协议”的这条声明移至“class-continuation分类”中。如果不行的话,就把协议单独放在一个头文件中,然后将其引入。
2. NS_ENUM
和NS_OPTIONS
Foundation框架定义了两个用于定义枚举类型的宏,NS_ENUM
和NS_OPTIONS
,他们的定义如下:
#define NS_ENUM(_type,_name) \
enum _name : _type _name; enum _name : _type
#define NS_OPTIONS(_type,_name) \
enum _name : _type _name; enum _name : _type
从上面定义可以发现其实这两个宏定义是一致的,区别在于它们的用途,前者主要用于对枚举值没什么特殊要求的枚举类型,而后者经常用于定义可以彼此组合的选项枚举值,如下面例子:
typedef NS_ENUM (NSUInteger, JKOrientation) {
JKOrientationEast,
JKOrientationSouth,
JKOrientationWest,
JKOrientationNorth
};
typedef NS_OPTIONS (NSUInteger, JKInterfaceOrientation) {
JKInterfaceOrientationUp = 1 << 0,
JKInterfaceOrientationDown = 1 << 1,
JKInterfaceOrientationLeft = 1 << 2,
JKInterfaceOrientationRight = 1 << 3,
};
- 应该使用枚举来表示状态机的状态,传递给方法的选项以及状态码等值,给这些值起个易懂的名字。
- 如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么就将各选项值定义为2的幂,以便按位或操作来将其组合起来。
- 用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
- 在处理枚举类型switch语句中不要实现default分支。这样的话,加入新的枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举。
3. archiveRootObject
归档失败
归档的使用简单易懂,是实现预缓存的一种常用方式,我按照如下方式实现预缓存:
+(NSString*)archivePath:(NSString*)archiveName userSpecific:(BOOL)isUserSpecific
{
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *tmp = nil;
if (isUserSpecific) {
NSString *currentUserName = [[NSUserDefaults standardUserDefaults] objectForKey:kKeyForCurrentUserName];
tmp = [NSString stringWithFormat:@"appCache/%@-%@.archiver",currentUserName,archiveName];
}else{
tmp = [NSString stringWithFormat:@"appCache/%@.archiver",archiveName];
}
NSString *archivePath = [cachePath stringByAppendingPathComponent:tmp];
return archivePath;
}
+(NSDictionary*)getCachedDataOf:(NSString*)cacheName userSpecific:(BOOL)isUserSpecific
{
NSString *archivePath = [JKAppCache archivePath:cacheName userSpecific:isUserSpecific];
NSDictionary *dic = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
return dic;
}
+(void)cacheData:(id)data forPageName:(NSString*)cacheName userSpecific:(BOOL)isUserSpecific;
{
NSString *archivePath = [JKAppCache archivePath:cacheName userSpecific:isUserSpecific];
if([NSKeyedArchiver archiveRootObject:data toFile:archivePath]){
NSLog(@"%@ archive succeed", cacheName);
}else{
NSLog(@"%@ archive failed", cacheName);
}
}
可是天公不作美啊,上述代码总是输出“** archive failed”
,然后就用模拟器先调试一把,断点到archiveRootObject
,查看获得的archivePath
变量,变量打印如下:
/Users/UserName/Library/Developer/CoreSimulator/Devices/BA2F8FD8-D1F8-4DFC-8F1B-E0CADFE635FF/data/Containers/Data/Application/EEEB6664-DB34-4865-AE5B-DF4BFF7BF2EA/Library/Caches/appCache/home.archiver
既然归档失败,那就首先看一下该路径下到底有什么,拷贝该路径,打开Finder,按Shift + CMD + G
快捷键,粘贴该路径,“崩”,该路径不存,那…./appCache目录存在吗?也不存在,但是…./Caches目录存在,那么答案粗来了,appCache目录不存在,怎么不存在该目录呢?其实上面代码就未曾建立过该目录,只是简单的在路径中添加了appCache路径而已。既然该目录不存在那就建立该目录,只需要更改获取路径函数,代码如下:
+(NSString*)archivePath:(NSString*)archiveName userSpecific:(BOOL)isUserSpecific
{
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
cachePath = [cachePath stringByAppendingPathComponent:@"appCache"];
BOOL isDir = NO;
NSError *error;
if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error];
}
NSString *tmp = nil;
if (isUserSpecific) {
NSString *currentUserName = [[NSUserDefaults standardUserDefaults] objectForKey:kKeyForCurrentUserName];
tmp = [NSString stringWithFormat:@"%@-%@.archiver",currentUserName,archiveName];
}else{
tmp = [NSString stringWithFormat:@"%@.archiver",archiveName];
}
NSString *archivePath = [cachePath stringByAppendingPathComponent:tmp];
return archivePath;
}
这样就欧了。