IOS基础理论知识复习(四)

   在看到大牛的知识点,发现很多知识点自己一知半解,能做项目但理论不够扎实,默默地去百度总结一下.放到这里和大家交流交流.

如有侵权,告知即删!

01.如何使用队列来避免资源抢夺?

后期跟新

02.数据持久化的几个方案

NSUserDefaults
plist(属性列表)
NSKeyedArchiver(对象归档)
iOS的嵌入式关系数据库SQLite3 (FMDB)
苹果公司提供的持久化工具 Core Data
上面几种方式,有一个共同的要素,就是应用的/Documents文件夹。每个应用都有自己的/Documents文件夹,且仅能读写各自/Documents文件中的内容
Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时备份该目录。例如,游戏应用可将游戏存档保存在该目录
tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用在该目录中查找应用的设置信息。iTunes同步设备时备份该目录

**NSUserDefaults:**
static NSString*constkey = @"key";
[[NSUserDefaults standardUserDefaults] setValue:@"YES"forKey: key];
[NSUserDefaults standardUserDefaults] valueForKey: key];
[userDefaults removeObjectForKey: key];
[userDefaults synchronize];

上面的示例代码基本就是NSUserDefaults所有用法了,虽然很简单,但还是有几点需要注意:
建议将所有的的key单独存放(好处自己领会)
NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。之前碰到个坑就是从服务器拿到数据部分用这种方式存储,服务器返回NSNull,我们这边也没有model层转,就直接存储了,导致app卡掉但并没有闪退之类,就是线程卡死的情况
同步问题,在适当的时候同步。因为synchronize的开销可能会很大,因为要比较内存中和存储中的所有用户偏好默认值,如果有好几百个key value 同步是非常消耗性能的。
偏好设置是专门用来保存应用程序的配置信息的,( 用过Settings.bundle的应该都很熟悉),所以一般不要在偏好设置中保存其他数据。
偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。

plist(属性列表)
首先需要知道什么是序列化对象(serialized object):指可以被转换为字节流以便于存储到文件中或通过网络进行传输的对象
可以被序列化的类型只有如下几种:
NSArray
NSMutableArray
NSDictionary
NSMutableDictionary
NSData
NSMutableData
NSString
NSMutableString
NSNumber
NSDate
还是直接上代码示例

/**
*  获取存储路径
*/- (NSString*)dataFilePath {
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentDirectory = paths[0];
return[documentDirectory stringByAppendingPathComponent:@"data.plist"];
//nsstring真强大
}

我们在app处于非活跃状态时存储一些东东

UIApplication* app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(appWillResignActive:) name: UIApplicationWillResignActiveNotification object: app];
- (void)appWillResignActive:(NSNotification*)notification {
NSString* filePath = [self dataFilePath];
NSArray* arr = @[@1,@2,@3,@4];   
 [arr writeToFile: filePath atomically:YES];
}

在我们需要这些东东的时候从文件中读取

NSString* filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath: filePath]) {
NSArray* arr = [[NSArray alloc] initWithContentsOfFile: filePath];
}

NSKeyedArchiver(对象归档):
在Cocoa中,Archiver是另一种形式的序列化,是任何对象都可实现的更常规的类型
说明:
只有遵守了NSCoding或 NSSecureCoding(更为安全的归档协议)协议,并且实现了协议里归档与解归档的方法的的类创建的对象才能够进行归档
最好也实现以下NSCopying,NSCopying与NSCoding一起实现好处在于允许复制对象,使用数据模型对象时有较大的灵活性
还是直接上代码

#import
@interface FourLines:NSObject
@property(copy, nonatomic)NSArray* lines;
@end
#import"FourLines.h"
//编解码的key 
static NSString *constklinesKey = @"klinesKey";
@implementationFourLines
#pragma mark -  NSCoding
- (void)encodeWithCoder:(NSCoder*)aCoder {   
[aCoder encodeObject: self.lines forKey: klinesKey];
}
- (nullable instancetype)initWithCoder:(NSCoder*)aDecoder {
self = [super init];
if(self) {
self.lines = [aDecoder decodeObjectForKey :klinesKey];   
}
returnself;
}
#pragma mark -  NSCopying
- (id)copyWithZone:(nullableNSZone*)zone {   
FourLines*copy= [[[self class] allocWithZone: zone] init];
NSMutableArray* linesCopy = [NSMutableArray array];
for(id line in self.lines) {       
[linesCopy addObject:[line copyWithZone: zone]];   
}
copy.lines= linesCopy;
return copy;
}
@end

写入数据,编码:文件路径还是用上面代码中定义的文件路径

- (void)appWillResignActive:(NSNotification*)notification {
NSString* filePath = [self dataFilePath];   
FourLines* lines = [[FourLines alloc]init];   
lines.lines= @[@"a",@"b",@"c",@"d"];
NSMutableData* data = [[NSMutableData alloc] init];
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data];   
[archiver encodeObject: lines forKey: kRootKey];   
[archiver finishEncoding];   
[data writeToFile: filePath atomically:YES]; 
}

读取数据,解码:

NSString* filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath: filePath]) {
NSData* data = [[NSMutableData alloc] initWithContentsOfFile: filePath];
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: data];        FourLines* four = [unarchiver decodeObjectForKey: kRootKey];       
[unarchiver finishDecoding];
for(int i =0; i <4; i++) {//to do}}
UIApplication* app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object: app];


03.说一下AppDelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);

当应用程序启动时(不包括已在后台的情况下转到前台),调用此回调。launchOptions是启动参数,假如用户通过点击push通知启动的应用,这个参数里会存储一些push通知的信息。

– (void)applicationDidBecomeActive:(UIApplication *)application;
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

当应用程序全新启动,或者在后台转到前台,完全激活时,都会调用这个方法。如果应用程序是以前运行在后台,这时可以选择刷新用户界面。

– (void)applicationWillResignActive:(UIApplication *)application;
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.

当应用从活动状态主动到非活动状态的应用程序时会调用这个方法。这可导致产生某些类型的临时中断(如传入电话呼叫或SMS消息)。或者当用户退出应用程 序,它开始过渡到的背景状态。使用此方法可以暂停正在进行的任务,禁用定时器,降低OpenGL ES的帧速率。游戏应该使用这种方法来暂停游戏。
调用时机可能有以下几种:锁屏,按HOME键,下接状态栏,双击HOME键弹出低栏,等情况。

– (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation NS_AVAILABLE_IOS(4_2);
// no equiv. notification. return NO if the application can’t open for some reason

当用户通过其它应用启动本应用时,会回调这个方法,url参数是其它应用调用openURL:方法时传过来的。
...............可以翻译官方文档自行查阅

04.NSCache优于NSDictionary的几点?

如果我们缓存使用得当,那么应用程序的响应速度就会提高。只有那种“重新计算起来很费事的数据,才值得放入缓存”,比如那些需要从网络获取或从磁盘读取的数据。
在构建缓存的时候很多人习惯用NSDictionary或者NSMutableDictionary,但是作者建议大家使用NSCache,它作为管理缓存的类,有很多特点要优于字典,因为它本来就是为了管理缓存而设计的。
NSCache优于NSDictionary的几点:
当系统资源将要耗尽时,NSCache具备自动删减缓冲的功能。并且还会先删减“最久未使用”的对象。
NSCache不拷贝键,而是保留键。因为并不是所有的键都遵从拷贝协议(字典的键是必须要支持拷贝协议的,有局限性)。
NSCache是线程安全的:不编写加锁代码的前提下,多个线程可以同时访问NSCache。
关于操控NSCache删减内容的时机
开发者可以通过两个尺度来调整这个时机:
缓存中的对象总数.
将对象加入缓存时,为其指定开销值。
对于开销值,只有在能很快计算出开销值的情况下,才应该考虑采用这个尺度,不然反而会加大系统的开销。
下面我们来看一下缓存的用法:缓存网络下载的数据

// Network fetcher class
typedef void(^EOCNetworkFetcherCompletionHandler)(NSData*data);
@interfaceEOCNetworkFetcher:NSObject
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler;
@end// Class that uses the network fetcher and caches results
@interfaceEOCClass:NSObject
@end
@implementationEOCClass{NSCache*_cache;}
- (id)init {if((self= [superinit])) {    _cache = [NSCachenew];
// Cache a maximum of 100
URLs_cache.countLimit =100;
/**
* The size in bytes of data is used as the cost,
* so this sets a cost limit of 5MB.
*/
_cache.totalCostLimit = 5*1024*1024;   
}
return self;
}
- (void)downloadDataForURL:(NSURL*)url {
NSData*cachedData = [ _cache objectForKey: url];
if(cachedData) {
// Cache hit:存在缓存,读取
[self useData: cachedData];   
}else{
// Cache miss:没有缓存,下载
EOCNetworkFetcher *fetcher = [[EOCNetworkFetcher alloc] initWithURL: url];             
[fetcher startWithCompletionHandler:^(NSData*data){       
[ _cache setObject: data forKey: url cost: data.length];           
[self useData: data];       
}];   
}}
@end

在这里,我们使用URL作为缓存的key,将总对象数目设置为100,将开销值设置为5MB。
05.知不知道Designated Initializer?使用它的时候有什么需要注意的问题?


图中的Designated Initializer标志说明,系统推荐你使用initWithNibName: bundle:方法创建UIViewController及其子类,不要用其他什么乱七八糟的方法创建对象.
Designated Initializer表示指定初始化函数(唯一的初始化出口)。
如果需要创建新的指定初始化函数,则新的指定初始化函数在内部调用父类的指定初始化函数。而旧的指定初始化函数降级为便利初始化函数,你必须重写便利初始化函数,并在里面转调新的指定初始化函数。
如果需要自己创建便利初始化函数,则在里面必须转调指定初始化函数。(和第二点一样)
一个类可以拥有多个指定初始化函数。你需要根据初始化数据源选择其中一个指定初始化函数。(不建议为一种初始化数据源创建多个指定初始化函数)。
..........更加详细的可以直接百度:Designated Initializer

你可能感兴趣的:(IOS基础理论知识复习(四))