在簡(jiǎn)書看到大牛的知識(shí)點(diǎn),發(fā)現(xiàn)很多知識(shí)點(diǎn)自己一知半解,能做項(xiàng)目但理論不夠扎實(shí),默默地去百度總結(jié)一下.放到這里和大家交流交流.
如有侵權(quán),告知即刪!
01.如何使用隊(duì)列來避免資源搶奪?
后期跟新
02.數(shù)據(jù)持久化的幾個(gè)方案
NSUserDefaults
plist(屬性列表)
NSKeyedArchiver(對(duì)象歸檔)
iOS的嵌入式關(guān)系數(shù)據(jù)庫(kù)SQLite3 (FMDB)
蘋果公司提供的持久化工具 Core Data
上面幾種方式,有一個(gè)共同的要素,就是應(yīng)用的/Documents文件夾。每個(gè)應(yīng)用都有自己的/Documents文件夾,且僅能讀寫各自/Documents文件中的內(nèi)容
Documents:保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時(shí)會(huì)備份該目錄。例如,游戲應(yīng)用可將游戲存檔保存在該目錄
tmp:保存應(yīng)用運(yùn)行時(shí)所需的臨時(shí)數(shù)據(jù),使用完畢后再將相應(yīng)的文件從該目錄刪除。應(yīng)用沒有運(yùn)行時(shí),系統(tǒng)也可能會(huì)清除該目錄下的文件。iTunes同步設(shè)備時(shí)不會(huì)備份該目錄
Library/Caches:保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時(shí)不會(huì)備份該目錄。一般存儲(chǔ)體積大、不需要備份的非重要數(shù)據(jù)
Library/Preference:保存應(yīng)用的所有偏好設(shè)置,iOS的Settings(設(shè)置)應(yīng)用會(huì)在該目錄中查找應(yīng)用的設(shè)置信息。iTunes同步設(shè)備時(shí)會(huì)備份該目錄
**NSUserDefaults:**
static NSString*constkey = @"key";
[[NSUserDefaults standardUserDefaults] setValue:@"YES"forKey: key];
[NSUserDefaults standardUserDefaults] valueForKey: key];
[userDefaults removeObjectForKey: key];
[userDefaults synchronize];
上面的示例代碼基本就是NSUserDefaults所有用法了,雖然很簡(jiǎn)單,但還是有幾點(diǎn)需要注意:
建議將所有的的key單獨(dú)存放(好處自己領(lǐng)會(huì))
NSUserDefaults可以存儲(chǔ)的數(shù)據(jù)類型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存儲(chǔ)其他類型,則需要轉(zhuǎn)換為前面的類型,才能用NSUserDefaults存儲(chǔ)。之前碰到個(gè)坑就是從服務(wù)器拿到數(shù)據(jù)部分用這種方式存儲(chǔ),服務(wù)器返回NSNull,我們這邊也沒有model層轉(zhuǎn),就直接存儲(chǔ)了,導(dǎo)致app卡掉但并沒有閃退之類,就是線程卡死的情況
同步問題,在適當(dāng)?shù)臅r(shí)候同步。因?yàn)閟ynchronize的開銷可能會(huì)很大,因?yàn)橐容^內(nèi)存中和存儲(chǔ)中的所有用戶偏好默認(rèn)值,如果有好幾百個(gè)key value 同步是非常消耗性能的。
偏好設(shè)置是專門用來保存應(yīng)用程序的配置信息的,( 用過Settings.bundle的應(yīng)該都很熟悉),所以一般不要在偏好設(shè)置中保存其他數(shù)據(jù)。
偏好設(shè)置會(huì)將所有數(shù)據(jù)保存到同一個(gè)文件中。即preference目錄下的一個(gè)以此應(yīng)用包名來命名的plist文件。
plist(屬性列表):
首先需要知道什么是序列化對(duì)象(serialized object):指可以被轉(zhuǎn)換為字節(jié)流以便于存儲(chǔ)到文件中或通過網(wǎng)絡(luò)進(jìn)行傳輸?shù)膶?duì)象
可以被序列化的類型只有如下幾種:
NSArray
NSMutableArray
NSDictionary
NSMutableDictionary
NSData
NSMutableData
NSString
NSMutableString
NSNumber
NSDate
還是直接上代碼示例
/**
* 獲取存儲(chǔ)路徑
*/- (NSString*)dataFilePath {
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentDirectory = paths[0];
return[documentDirectory stringByAppendingPathComponent:@"data.plist"];
//nsstring真強(qiáng)大
}
我們?cè)赼pp處于非活躍狀態(tài)時(shí)存儲(chǔ)一些東東
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];
}
在我們需要這些東東的時(shí)候從文件中讀取
NSString* filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath: filePath]) {
NSArray* arr = [[NSArray alloc] initWithContentsOfFile: filePath];
}
NSKeyedArchiver(對(duì)象歸檔):
在Cocoa中,Archiver是另一種形式的序列化,是任何對(duì)象都可實(shí)現(xiàn)的更常規(guī)的類型
說明:
只有遵守了NSCoding或 NSSecureCoding(更為安全的歸檔協(xié)議)協(xié)議,并且實(shí)現(xiàn)了協(xié)議里歸檔與解歸檔的方法的的類創(chuàng)建的對(duì)象才能夠進(jìn)行歸檔
最好也實(shí)現(xiàn)以下NSCopying,NSCopying與NSCoding一起實(shí)現(xiàn)好處在于允許復(fù)制對(duì)象,使用數(shù)據(jù)模型對(duì)象時(shí)有較大的靈活性
還是直接上代碼
#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
寫入數(shù)據(jù),編碼:文件路徑還是用上面代碼中定義的文件路徑
- (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];
}
讀取數(shù)據(jù),解碼:
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];
<br />
03.說一下AppDelegate的幾個(gè)方法?從后臺(tái)到前臺(tái)調(diào)用了哪些方法?第一次啟動(dòng)調(diào)用了哪些方法?從前臺(tái)到后臺(tái)調(diào)用了哪些方法?
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);
當(dāng)應(yīng)用程序啟動(dòng)時(shí)(不包括已在后臺(tái)的情況下轉(zhuǎn)到前臺(tái)),調(diào)用此回調(diào)。launchOptions是啟動(dòng)參數(shù),假如用戶通過點(diǎn)擊push通知啟動(dòng)的應(yīng)用,這個(gè)參數(shù)里會(huì)存儲(chǔ)一些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.
當(dāng)應(yīng)用程序全新啟動(dòng),或者在后臺(tái)轉(zhuǎn)到前臺(tái),完全激活時(shí),都會(huì)調(diào)用這個(gè)方法。如果應(yīng)用程序是以前運(yùn)行在后臺(tái),這時(shí)可以選擇刷新用戶界面。
– (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.
當(dāng)應(yīng)用從活動(dòng)狀態(tài)主動(dòng)到非活動(dòng)狀態(tài)的應(yīng)用程序時(shí)會(huì)調(diào)用這個(gè)方法。這可導(dǎo)致產(chǎn)生某些類型的臨時(shí)中斷(如傳入電話呼叫或SMS消息)?;蛘弋?dāng)用戶退出應(yīng)用程 序,它開始過渡到的背景狀態(tài)。使用此方法可以暫停正在進(jìn)行的任務(wù),禁用定時(shí)器,降低OpenGL ES的幀速率。游戲應(yīng)該使用這種方法來暫停游戲。
調(diào)用時(shí)機(jī)可能有以下幾種:鎖屏,按HOME鍵,下接狀態(tài)欄,雙擊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
當(dāng)用戶通過其它應(yīng)用啟動(dòng)本應(yīng)用時(shí),會(huì)回調(diào)這個(gè)方法,url參數(shù)是其它應(yīng)用調(diào)用openURL:方法時(shí)傳過來的。
...............可以翻譯官方文檔自行查閱
<br />
04.NSCache優(yōu)于NSDictionary的幾點(diǎn)?
如果我們緩存使用得當(dāng),那么應(yīng)用程序的響應(yīng)速度就會(huì)提高。只有那種“重新計(jì)算起來很費(fèi)事的數(shù)據(jù),才值得放入緩存”,比如那些需要從網(wǎng)絡(luò)獲取或從磁盤讀取的數(shù)據(jù)。
在構(gòu)建緩存的時(shí)候很多人習(xí)慣用NSDictionary或者NSMutableDictionary,但是作者建議大家使用NSCache,它作為管理緩存的類,有很多特點(diǎn)要優(yōu)于字典,因?yàn)樗緛砭褪菫榱斯芾砭彺娑O(shè)計(jì)的。
NSCache優(yōu)于NSDictionary的幾點(diǎn):
當(dāng)系統(tǒng)資源將要耗盡時(shí),NSCache具備自動(dòng)刪減緩沖的功能。并且還會(huì)先刪減“最久未使用”的對(duì)象。
NSCache不拷貝鍵,而是保留鍵。因?yàn)椴⒉皇撬械逆I都遵從拷貝協(xié)議(字典的鍵是必須要支持拷貝協(xié)議的,有局限性)。
NSCache是線程安全的:不編寫加鎖代碼的前提下,多個(gè)線程可以同時(shí)訪問NSCache。
關(guān)于操控NSCache刪減內(nèi)容的時(shí)機(jī)
開發(fā)者可以通過兩個(gè)尺度來調(diào)整這個(gè)時(shí)機(jī):
緩存中的對(duì)象總數(shù).
將對(duì)象加入緩存時(shí),為其指定開銷值。
對(duì)于開銷值,只有在能很快計(jì)算出開銷值的情況下,才應(yīng)該考慮采用這個(gè)尺度,不然反而會(huì)加大系統(tǒng)的開銷。
下面我們來看一下緩存的用法:緩存網(wǎng)絡(luò)下載的數(shù)據(jù)
// 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,將總對(duì)象數(shù)目設(shè)置為100,將開銷值設(shè)置為5MB。
05.知不知道Designated Initializer?使用它的時(shí)候有什么需要注意的問題?

圖中的Designated Initializer標(biāo)志說明,系統(tǒng)推薦你使用initWithNibName: bundle:方法創(chuàng)建UIViewController及其子類,不要用其他什么亂七八糟的方法創(chuàng)建對(duì)象.
Designated Initializer表示指定初始化函數(shù)(唯一的初始化出口)。
如果需要?jiǎng)?chuàng)建新的指定初始化函數(shù),則新的指定初始化函數(shù)在內(nèi)部調(diào)用父類的指定初始化函數(shù)。而舊的指定初始化函數(shù)降級(jí)為便利初始化函數(shù),你必須重寫便利初始化函數(shù),并在里面轉(zhuǎn)調(diào)新的指定初始化函數(shù)。
如果需要自己創(chuàng)建便利初始化函數(shù),則在里面必須轉(zhuǎn)調(diào)指定初始化函數(shù)。(和第二點(diǎn)一樣)
一個(gè)類可以擁有多個(gè)指定初始化函數(shù)。你需要根據(jù)初始化數(shù)據(jù)源選擇其中一個(gè)指定初始化函數(shù)。(不建議為一種初始化數(shù)據(jù)源創(chuàng)建多個(gè)指定初始化函數(shù))。
..........更加詳細(xì)的可以直接百度:Designated Initializer