1. 程式人生 > >iOS應用開發基礎(四)基礎知識(資料儲存和多執行緒)

iOS應用開發基礎(四)基礎知識(資料儲存和多執行緒)

本文可能涉及很多零碎的知識點,其中包括iOS應用開發的相關基礎知識。以後會針對每個條目在進行深入研究,這裡只是先做一個相關知識的概述總結。

iOS的資料儲存

大多數iOS程式其功能總結為:提供一套介面,幫助使用者管理特定資料。在這個過程中,不同物件各司其職:模型物件負責儲存資料,檢視物件負責顯示資料,控制器物件負責在模型物件與檢視物件之間同步資料。

固化和解固

由iOS SDK提供的一種儲存和讀取物件的機制。固化某個物件的時候,會將其所有屬性存入指定的檔案中。解固某個物件時,會從指定的檔案讀取相應的資料,然後根據資料還原物件。

為了固化和解固某個物件,必須要遵守NSCoding協議,並且實現兩個必需方法:encodeWithCoder方法:和initWithCoder:方法。

-(void)encodeWithCoder:(NSCode *)aCoder{
    [aCoder encodeObject:self.itemName forKey:@"itemName"];
}
-(instancetype) initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    if(self){
            _itermName = [aDecoderdecodeObjectForKey:@"itemName"];
    }
}

存放路徑

iOS應用可以在執行時載入應用程式包中的檔案。要獲得應用程式包中的某個檔案的全路徑,需要首先得到代表應用程式包的NSBundle物件,然後通過該物件得到某個檔案的全路徑,程式碼如下:

NSBundle *applicationBundle = [NSBundle mainBundle];
NSString *path = [applicationBundle pathForResource:@"myImage" ofType:@"png"];

如果應用程式需要儲存程式引數、選項相關的少量資料,則可以使用NSUserDefaults進行儲存;如果應用程式只有少量資料需要儲存,那麼使用屬性列表就可以了;如果應用程式有大量資料進行儲存、訪問,就需要藉助於資料庫了。iOS內建SQLite資料庫是一個真正輕量級的資料庫,他沒有後臺程式,整個資料庫對應一個檔案。並有兩套API:基於c語言風格的libsqlite3.dylib和麵向物件的Core Data。

應用程式沙盒目錄

 1. Document:除了基於NSUserDefaults的首選項設定之外,應用程式的資料、檔案都儲存在該目錄下
 2. Library:基於NSUserDefaults的首選項引數儲存在Library/Preference目錄下。
 3. Library/Caches:存放執行時生成的保留資料。iTunes或者iClound不會同步該資料。
 4. Library/Preferences: 存放所有偏好資料。可以使用NSUserDefaults類
 5. tmp:該目錄提供應用程式儲存的歷史檔案,當iOS執行同步的時候,iTunes不會備份tmp目錄下的檔案。
 因此當應用程式不在需要某個臨時檔案時,應該負責刪除tmp目錄下的臨時檔案,避免佔用系統空間。執行時的臨時檔案。

儲存、讀取資料

前面介紹了固化的存放路徑,下面要講的是:1.如何儲存、讀取資料;2.何時儲存、讀取資料

儲存

通過 NSKeyedArchiver類儲存物件傳送archiveRootObject:toFile:訊息

-(BOOL)saveChagne
{
    NSString *path = [self itemArchivePath];
    return [NSKeyedArchiver archiveRootObject:self.privateItems  toFile :path];
}

上面的工作原理是:

 1. archiveRootObject:toFile:會先建立一個NSKeyedArchiver物件。
 2. 然後,archiveRootObject:toFile:會向privateItems傳送encodeWithCoder:訊息,並傳入NSKeyedArchiver物件作為第一個引數。
 3. privateItems的encodewithCoder:方法會向其包含的多個物件一次傳送encodeWithCoder訊息,
 並傳入NSKeyedArchiver物件。這項BNRItem物件都會將其屬性編碼至同一個NSKeyedArchiver物件。
 4. 當所有的物件都完成編碼後,NSKeyedArchiver物件就會將資料寫入指定的檔案中。

何時儲存

一般情況是在使用者按下裝置的主螢幕按鈕後,AppDelegate物件會收到applicationDidEnterBackground:訊息之後,傳送saveChange訊息;

讀取

主要使用NSKeyedUnarchiver類。

-(instancetype)initPrivate
{
    self = [super init];
    NSString *psth = [self itemArchivePath];
    _privateItems = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    if(!_privateItems){
        _privateItems = [[NSMutableArray alloc] init];
    }
    return self;
}

iOS多執行緒

iOS大致提供瞭如下三種多執行緒程式設計技術。

 1. NSThread實現多執行緒。
 2. NSOperation與NSOperationQueue實現多執行緒。
 3. 使用GCD(Grand Central Dispatch)實現多執行緒。

NSThread的一些方法

建立一個新執行緒物件。

- initWithTarget:selector:object:   

建立並啟動新執行緒。

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)arg;   

上面兩種方法的本質都是將target物件的selector方法轉化為執行緒執行體,其中selector方法最多可以接受一個引數,而arg就代表創個selector方法的引數。

*currentThread 屬性返回當前正在執行的執行緒物件。
除此之外,可以通過setName:方法為執行緒設定名字,也可以通過name方法返回指定執行緒的名字。

執行緒的狀態:

備註:啟動執行緒使用start方法,執行緒啟動之後並不是立即進入執行狀態,執行緒內啟動後處於就緒狀態,當系統排程執行緒後, 執行緒才會進入執行狀態。
如果程式希望子執行緒的start後立刻執行,程式可以使用NSThread sleepForTimeInterval:0.001讓當前執行的執行緒睡眠1毫秒。

終止子執行緒:

 1. 執行緒正常結束。
 2. 執行緒執行過程中出現錯誤。
 3. 直接呼叫NSThread的exit方法,來終止當前正在執行的執行緒。

在iOS規定中,只能在UI執行緒中修改UI控制元件的屬性。所以當子執行緒執行“任務”完成後,如果需要通過UI控制元件來顯示子執行緒中的資料,則通常會呼叫performSelectorOnMainThread:withObject:waitUntilDone:方法完成。

執行緒的同步與執行緒的通訊

執行緒同步:

[email protected]實現同步。被@synchronize修飾的程式碼塊可簡稱同步程式碼塊。格式如下:

@synchronize(obj)
{
...
//同步程式碼塊。obj就是同步監視器。通過是可能被併發訪問的共享資源充當同步監視器。
}

Foundation框架中很多類都有可變和不可變兩種版本,比如NSString, NSArray都是不可變,他們永遠是執行緒安全的。但是NSMutableString,NSMutaleArray就是可變得,執行緒不安全的。

釋放對同步監視器的鎖定:

 1. 塊執行結束;
 2. return、goto等語句結束程式碼塊。
 3. 出現錯誤、異常等。但是sleep不會釋放監視器。

同步鎖:NSLock

先獲得NSLock物件例項,然後

[lock lock]
 ......
[lock unlock];

NSCondition控制執行緒通訊

雖然執行緒在系統內執行時,執行緒的排程具有一定的透明性,程式通常無法準確的控制執行緒輪換執行,但我們可以通過一些機制來保證執行緒協調執行,也就是處理執行緒之間的通訊。

Foundation提供了一個NSCondition類來處理執行緒通訊,NSCondition實現了NSLocking協議,因此也可以呼叫lock、unlock來實現執行緒同步。NSCondition可以讓那些已經鎖定NSCondition物件卻無法繼續執行的執行緒釋放NSCondition物件,NSCondition物件也可以喚醒其他處於等待狀態的執行緒。
主要是三個函式:

-wait:導致當前一直等待,直到其他執行緒呼叫該NSCondition的signal或者broadcaset方法來喚醒該執行緒。
-signal:喚醒再次NSCondition物件等待的單個執行緒。如果執行緒都在該NSCondition物件等待,則會選擇性喚醒其中一個執行緒。
-broadcast:喚醒在此NSCondition物件等待的所有執行緒。

使用GCD實現多執行緒。

GCD的兩個核心概念:

1.佇列:佇列負責管理開發者提交的任務
2.任務:任務就是使用者提交給佇列的工作單位,這些任務提交給佇列底層維護的執行緒池執行,因此這些任務會以多執行緒的方式執行。

主要是兩個步驟:

1.建立佇列。
2.將任務提交給佇列。

建立佇列函式:

dispatch_queue_t dispatch_get_current_queue(void);

dispatch_queue_t dispatch_get_global_queue(long identifier, <#unsigned long flags#>)

…..其他具體的參考開發文件

NSOperation與NSOperationQueue實現多執行緒。

基本理論:

NSOperationQueue:代表一個FIFO的佇列,它負責管理系統提交的多個NSOperation,NSOperationQueue底層維護一個執行緒池,會按照順序啟動執行緒來執行提交給該佇列的NSOperation任務。

NSOperation:代表一個多執行緒任務。NSOperation有兩個子類:1.NSInvocationOperation、NSBlockOperation。開發者會自己實現子類,也可以直接使用該子類。

步驟:

1.建立NSOperationQueue佇列,病設定相關屬性。
2.建立NSOperation子類物件,並將該物件提交給NSOperationQueue佇列,該佇列將會按照一次啟動每個NSOperation任務。