Preferences and Settings Programming Guide

關于首選項和設置

首選項是您持久存儲的信息,并用于配置您的應用程序。應用程序通常會向用戶公開偏好設置,以便他們自定義應用程序的外觀和行為。大多數首選項都使用Cocoa首選項系統(稱為用戶默認系統)本地存儲。應用程序還可以使用鍵值存儲在用戶的iCloud帳戶中存儲首選項。

用戶默認系統和鍵值存儲都設計用于在屬性列表中存儲簡單數據類型 - 字符串,數字,日期,布爾值,URL,數據對象等。使用屬性列表也意味著您可以使用數組和字典類型來組織偏好數據。首先將其編碼到NSData對象中,也可以將其他對象存儲在屬性列表中。

概述

應用程序可以通過多種方式集成首選項,包括以編程方式覆蓋整個代碼中的各個方面,并作為用戶界面的一部分。 iOS和Mac應用都支持偏好設置。

你決定你想要設置什么偏好

每個應用的偏好設置都不同,您可以決定要配置的應用程序的哪些部分。配置包括從代碼中檢查存儲的首選項的值,并根據該值執行操作。因此,偏好值本身應該始終是簡單的,并具有特定的意義,然后由您的應用程序實現。

相關部分:什么是好的偏好?

應用提供自己的首選項界面

因為每個應用程序的偏好都不同,所以應用程序本身負責決定如何最好地向用戶呈現這些偏好設置(如果有的話)。 iOS和OS X都提供了一些標準的地方,您可以使用首選項界面,但您仍然負責設計該界面并在適當的時間顯示該界面。

相關部分:提供首選界面

應用程序訪問首選項使用用戶默認對象

應用程序使用用戶默認對象(即NSUserDefaults對象(iOS和OS X))或NSUserDefaultsController對象(僅限OS X)訪問本地存儲的首選項。除了檢索偏好值之外,應用程序還可以使用此對象注冊首選項的默認值,并管理首選項系統的其他方面。

相關章節:訪問偏好值

關于用戶默認系統

用戶默認系統管理每個用戶的首選項的存儲。大多數偏好設置都會持續存儲,因此在應用程序的后續啟動周期內不會更改。應用程序使用首選項來跟蹤用戶啟動的和程序啟動的配置更改。

什么是好的偏好?

在定義應用程序的首選項時,最好盡可能使用簡單的值和數據類型。首選項系統圍繞屬性列表數據類型構建,如字符串,數字和日期。雖然您可以使用NSData對象在首選項中存儲任意對象,但在大多數情況下不建議執行此操作。

永久存儲對象意味著您的應用程序必須在某個時間對該對象進行解碼。在首選項的情況下,存儲的對象意味著每當您訪問該偏好時對該對象進行解碼。這也意味著您的應用程序的較新版本必須確保能夠使用較早版本的應用程序對創建和寫入磁盤的對象進行解碼,這可能會容易出錯。

更好的方法是存儲簡單的字符串和值,并使用它們來創建應用程序需要的對象。存儲簡單的值意味著您的應用程序可以隨時訪問該值。從發布到發布的唯一的事情就是解釋簡單的值和應用程序創建的對象。

提供首選接口

對于面向用戶的首選項,表1-1列出了向用戶顯示這些首選項的選項。從這個表中可以看出,大多數選項都涉及創建用于管理和呈現首選項的自定義用戶界面。如果您正在創建iOS應用程序,則可以使用“設置”軟件包來顯示首選項,但是您應該僅在用戶不經常更改的設置時執行此操作。

表1-1為用戶顯示首選項的選項
偏愛
iOS版
OS X
經常更改的首選項
自定義UI
自定義UI
不經常更改的首選項
設置包
自定義UI
注意:可能會頻繁更改的首選項的示例包括游戲的音量級別或控制選項。郵件應用程序中的電子郵件地址和服務器設置可能不頻繁更改的首選項的示例。對于iOS應用程序,您最終可以決定是否適用于從“設置”應用程序或應用程序內部顯示偏好設置。
應用程序菜單中的“首選項”菜單項可以訪問Mac應用程序中的首選項。使用Xcode模板創建的Cocoa應用程序會自動為您提供一個菜單項。當用戶選擇此菜單項時,您有責任提供適當的用戶界面。您可以通過在應用程序委托中定義一個操作方法來提供該用戶界面,該方法顯示自定義首選項窗口,并將該操作方法連接到Interface Builder中的菜單項。

沒有標準的方式可以在iOS應用程式內顯示自訂偏好設定。您可以通過多種方式集成首選項,包括在標簽欄界面中使用單獨的選項卡,或者使用應用程序屏幕之一中的自定義按鈕。通常應使用不同的視圖控制器來呈現首選項,以便當該視圖控制器被用戶忽略時可以記錄首選項的改變。

偏好組織

首選項分為域,每個域具有名稱和特定用途。例如,有一個應用程序特定首選項的域,另一個適用于所有應用程序的系統范圍的首選項。所有的偏好設置都是基于每個用戶存儲和訪問的。不支持在用戶之間共享首選項。

每個偏好有三個組成部分:

存儲它的域
它的名稱(指定為NSString對象)
它的值可以是任何屬性列表對象(NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary)
首選項的生命周期取決于您存儲的域。某些域通過將首選項寫入用戶的默認數據庫來持久存儲首選項。這種喜好從一個應用程序啟動到下一個應用程序仍然存在。其他域以更易變的方式存儲偏好,僅在相應的用戶默認對象的生命周期內保留偏好值。

搜索給定首選項的值通過NSUserDefaults對象的搜索列表中的域進行。只搜索搜索列表中的域,并按照表1-2所示的順序進行搜索,從NSArgumentDomain域開始。當找到具有指定名稱的首選項時,搜索結束。如果多個域包含相同的首選項,則該值取自離搜索列表開頭最近的域。

表1-2域的搜索順序


NSArgumentDomain
揮發物
應用程序(由應用程序的標識符識別)
一貫
NSGlobalDomain
一貫
語言(由語言名稱識別)
揮發物
NSRegistrationDomain
揮發物
參數域
參數域包括從命令行參數設置的值(如果您從命令行啟動應用程序),并由NSArgumentDomain常量標識。從命令行設置的值將被系統自動放入此域。要向此域添加值,請在命令行中指定首選項名稱(在連字符前面),并使用相應的值進行跟蹤。例如,以下命令啟動Xcode并將其IndexOnOpen首選項的值設置為NO:

localhost> Xcode.app/Contents/MacOS/Xcode-IndexOnOpen NO
從命令行設置的首選項臨時覆蓋存儲在用戶的默認數據庫中的已建立的值。在上述示例中,將IndexOnOpen首選項設置為NO會阻止Xcode自動對項目建立索引,即使在用戶默認數據庫中將首選項設置為YES。

應用程序域

應用程序域包含存儲在當前用戶的用戶默認數據庫中的特定于應用程序的首選項。當您使用共享的NSUserDefaults對象(或OS X中的NSUserDefaultsController對象)來編寫首選項時,這些首選項將自動放置在此域中。

由于此域名是應用程序特定的,因此域的內容與您的應用程序的包標識符相關。該域的內容存儲在由系統管理的文件中。目前,該文件位于$ HOME / Library / Preferences /目錄中,其中$ HOME是應用程序的主目錄或用戶的主目錄(取決于平臺以及您的應用程序是否在沙箱中)。用戶默認數據庫文件的名稱為<ApplicationBundleIdentifer> .plist,其中<ApplicationBundleIdentifer>是您的應用程序的包標識符。您不應該直接修改此文件,但可以在調試期間檢查它,以確保您的應用程序正在寫入偏好值。

全球域名

全局域包含適用于所有應用程序的首選項,并由NSGlobalDomain常量標識。系統框架通常使用此域來存儲系統范圍的值,應用程序不應使用該域來存儲特定于應用程序的值。如果要在全局域中更改首選項的值,請使用新值將相同的首選項寫入應用程序域。

系統框架如何使用此域的示例:

NSRuleView類的實例將用戶的首選測量單位存儲在AppleMeasurementUnits鍵中。使用此存儲位置會導致所有應用程序中的標尺視圖使用相同的單位。
系統使用AppleLanguages鍵將用戶的首選語言存儲為字符串數組。例如,用戶可以將英語指定為首選語言,其次是西班牙語,法語,德語,意大利語和瑞典語。
語言域
對于AppleLanguages首選項中的每種語言,系統會在名稱基于語言名稱的域中記錄特定于語言的首選項值。每個特定于語言的域包含相應區域設置的首選項。 Foundation框架中的許多類(如NSDate,NSDateFormatter,NSTimeZone,NSString和NSScanner類)使用此語言環境信息來修改其行為。例如,當您請求NSCalendarDate對象的字符串表示時,NSCalendarDate對象使用區域設置信息來查找用戶首選語言的月份和星期幾的名稱。

注冊域

如果在其他域中未明確設置給定的首選項,則注冊域定義要使用的一組默認值。在啟動時,應用程序可以調用NSUserDefaults的registerDefaults:方法為重要的首選項指定一組默認值。當應用程序第一次啟動時,大多數首選項都沒有值,因此檢索它們將產生未定義的結果。注冊一組默認值可確保您的應用程序始終具有已知的一組值來操作。

只能使用registerDefaults:方法設置注冊域的內容。

使用默認工具查看首選項

在OS X中,默認的命令行工具提供了一種檢查用戶默認數據庫內容的方法。 在應用程序開發過程中,您可以使用此工具來驗證應用程序正在寫入磁盤的首選項。 為此,您可以使用終端應用程序中以下表單的命令:

默認值為<application-bundle-identifier>

要閱讀全局域的內容,您可以使用以下命令:

默認值讀取NSGlobalDomain

有關使用默認工具讀取和寫入首選項值的更多信息,請參閱默認值手冊頁。

訪問偏好值

您使用NSUserDefaults類來訪問您的應用程序的首選項。每個應用程序都提供了此類的單個實例,可從standardUserDefaults類方法訪問。您可以使用共享用戶默認對象:

在啟動時指定應用程序偏好設置的任何默認值。
獲取并設置存儲在應用程序域中的個人偏好值。
刪除首選項值。
檢查volatile偏好域的內容。
使用Cocoa綁定的Mac應用程序可以使用NSUserDefaultsController對象自動設置和獲取首選項。您通常將此類對象添加到用于顯示面向用戶的首選項的相同nib文件。將用戶界面控件綁定到用戶默認控制器中的項目,該控件處理在用戶默認數據庫中獲取和設置值的過程。

首選項值必須是標準屬性列表對象類型之一:NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary。 NSUserDefaults類還提供內置操作,用于將NSURL對象存儲為首選項值。有關屬性列表及其內容的更多信息,請參閱“屬性列表編程指南”。

注冊您的應用程序的默認首選項

在發布時,一個應用程序應該為其期望存在和有效的任何首選項注冊默認值。當您請求從未設置的首選項的值時,NSUserDefaults類的方法返回適用于數據類型的默認值。對于數字標量值,這通常意味著返回0,但對于字符串和其他對象,它意味著返回零。如果這些標準默認值不適用于您的應用程序,則可以使用registerDefaults:方法注冊自己的默認值。此方法將您的自定義默認值放置在NSRegistrationDomain域中,這將導致在未明確設置首選項時返回它們。

調用registerDefaults:方法時,必須提供一個您需要注冊的所有默認值的字典。清單2-1顯示了一個iOS應用程序在啟動周期早期注冊其默認值的示例。您可以隨時注冊默認值,但在嘗試檢索任何首選項值之前,應始終注冊它們。

清單2-1注冊默認首選項值

   // Register the preference defaults early.
    NSDictionary *appDefaults = [NSDictionary
        dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"CacheDataAgressively"];
    [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];

   // Other initialization...
}

在為標量類型注冊默認值時,使用NSNumber對象來指定數字的值。如果要注冊其值為URL的首選項,請先使用NSKeyedArchiver的archivedDataWithRootObject:方法對NSData對象中的URL進行編碼。雖然您可以對其他類型的對象使用類似的技術,但是當有更簡單的選項可用時,您應該避免這樣做。

獲取和設置偏好值

您可以使用NSUserDefaults類的方法獲取并設置首選項值。此類具有獲取和設置類型為Boolean,integer,float和double的標量值的首選項的方法。它還具有獲取和設置其值為NSData,NSDate,NSString,NSNumber,NSArray,NSDictionary和NSURL類型的對象的首選項的方法。有兩種情況可以獲得偏好值,您可以在其中設置它們:

獲取偏好值:

當您需要使用該值配置您的應用程序的行為。
當您需要在首選項界面中顯示該值時。
當用戶在首選項界面中更改它們時,設置首選項值。
以下代碼顯示了如何在代碼中獲取首選項值。在此示例中,代碼檢索CacheDataAggressively鍵的值,該值是應用程序可能用于確定其緩存策略的自定義鍵。像這樣的代碼可以在任何地方使用來處理應用程序的自定義配置。如果要向用戶顯示此特定偏好值,則可以使用類似的代碼來配置首選項界面的控件。

if ([[NSUserDefaults standardUserDefaults] boolForKey:@"CacheDataAggressively"]) {
   // Delete the backup file.
}

要以編程方式設置首選項值,可以調用NSUserDefaults的相應設置器方法。 設置對象值時,必須使用setObject:forKey:方法。 調用此方法時,必須確保對象是標準屬性列表類型之一。 以下示例基于應用程序的首選項界面的狀態設置一些首選項。

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if ([cacheAgressivelyButton state] == NSOnState) {
   // The user wants to cache files aggressively.
   [defaults setBool:YES forKey:@"CacheDataAggressively"];
   [defaults setObject:[NSDate dateWithTimeIntervalSinceNow:(3600 * 24 * 7)]
             forKey:@"CacheExpirationDate"]; // Set a 1-week expiration
} else {
    // The user wants to use lazy caching.
   [defaults setBool:NO forKey:@"CacheDataAggressively"];
   [defaults removeObjectForKey:@"CacheExpirationDate"];
}

您不必顯示首選項界面來管理所有值。您的應用程序可以使用首選項來緩存有趣的信息。例如,NSWindow對象將其當前位置存儲在用戶默認系統中。該數據允許他們在下次用戶啟動應用程序時返回到相同的位置。

同步和檢測偏好變化

由于NSUserDefaults類緩存值,有時需要將緩存的值與用戶默認數據庫的當前內容進行同步。您的應用程序并不總是修改用戶默認數據庫的唯一實體。在iOS中,“設置”應用可以修改具有“設置”包的應用的首選項的值。在OS X中,系統和其他應用程序可能會修改首選項值以響應用戶操作。例如,如果用戶更改首選語言,則系統將新值寫入用戶默認數據庫。在OS X v10.5及更高版本中,共享的NSUserDefaults對象將以周期性間隔自動同步其緩存。但是,應用程序可以手動調用synchronized方法來強制更新緩存的值。

要檢測何時發生偏好值的更改,應用程序也可以注冊通知NSUserDefaultsDidChangeNotification。共享的NSUserDefaults對象將發送此通知到您的應用程序,只要它檢測到位于其中一個持久性域中的首選項的更改。您可以使用此通知來響應可能影響用戶界面的更改。例如,您可以使用它來檢測用戶首選語言的更改,并適當更新您的應用內容。

使用Cocoa綁定管理首選項

Mac應用程序可以使用Cocoa綁定從其用戶界面直接設置首選項值。使用綁定修改首選項涉及將NSUserDefaultsController對象添加到適當的nib文件,并將控件的值綁定到用戶默認數據庫中的首選項值。當您的應用程序顯示界面時,用戶默認控制器會自動從用戶默認數據庫加載值,并使用它們設置控件的值。類似地,當用戶更改控件中的值時,用戶默認控制器更新用戶默認數據庫中的值。

有關如何使用NSUserDefaultsController類將優選值綁定到用戶界面的更多信息,請參閱Cocoa Bindings編程主題中的用戶默認值和綁定。

使用Core Foundation管理首選項

核心基礎框架提供了自己的一組接口,用于訪問存儲在用戶默認數據庫中的首選項。NSUserDefaults類一樣,您可以使用Core Foundation函數來獲取和設置首選項值并同步用戶默認數據庫與NSUserDefaults不同,您可以使用Core Foundation函數為不同的應用程序和不同的計算機編寫首選項。請注意,修改某些首選項域(不屬于當前應用程序和用戶的域)需要root權限(或OS X v10。 6之前的管理員權限);有關如何獲得適當權限的信息,請參閱授權服務編程指南在沙箱中安裝的應用程序無法對應用程序域名進行寫入。

有關獲取和設置首選項的核心基礎功能的信息,請參閱“首選項實用程序參考”。

使用核心基礎設置偏好值

首選存儲為鍵值對,密鑰必須是CFString對象,但該值可以是任何Core Foundation屬性列表值(請參閱Core Foundation的“屬性列表編程主題”),包括容器類型例如,您可能會使用一個名為defaultWindowWidth的鍵來定義應用程序創建的任何新窗口的寬度(以像素為單位)。其值很可能是CFNumber類型。您還可以決定將窗口寬度和高度合并為名為defaultWindowSize的單個首選項,并將其值設為包含兩個CFNumber對象的CFArray對象。

清單2-2中的代碼演示了如何為應用程序MyTextEditor創建一個簡單的首選項。該示例將應用程序的默認文本顏色設置為藍色。

清單2-2編寫一個簡單的默認值

CFStringRef textColorKey = CFSTR("defaultTextColor");
CFStringRef colorBLUE = CFSTR("BLUE");

// Set up the preference.
CFPreferencesSetAppValue(textColorKey, colorBLUE,
        kCFPreferencesCurrentApplication);

// Write out the preference data.
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);

請注意,CFPreferencesSetAppValue本身不足以創建新的首選項。需要調用CFPreferencesAppSynchronize來實際保存該值。如果您正在編寫多個首選項,則在設置最后一個值后才能同步一次,而不是在設置每個單獨的值后進行同步。例如,如果實現首選項窗格,則只有當用戶按下“確定”按鈕時,才能同步。在其他情況下,您可能不想在應用程序退出之前完全同步,但請注意,如果應用程序崩潰,所有未保存的首選項設置將丟失。

使用核心基礎獲得偏好值
找到和檢索首選項值的最簡單的方法是使用CFPreferencesCopyAppValue函數。此調用按順序搜索各種偏好域,直到找到您指定的密鑰。如果在不太特定的域 - 任何應用程序中設置了首選項,例如 - 如果找不到更具體的版本,則使用此調用檢索值。清單2-3顯示了如何檢索列表2-2中保存的文本顏色偏好。

列表2-3讀取簡單的默認值

CFStringRef textColorKey = CFSTR("defaultTextColor");
CFStringRef textColor;

// Read the preference.
textColor = (CFStringRef)CFPreferencesCopyAppValue(textColorKey,
        kCFPreferencesCurrentApplication);
// When finished with value, you must release it
// CFRelease(textColor);

從首選項返回的所有值都是不可變的,即使您剛剛使用可變對象設置值。

在iCloud中存儲首選項

應用程序可以使用iCloud鍵值存儲在用戶的其他計算機和iOS設備上與其他本身的實例共享少量數據。鍵值存儲用于簡單的數據類型,如可能用于首選項的數據類型。例如,雜志應用程序可能會存儲用戶正在讀取的當前問題和頁碼,以便應用程序的其他實例可以在啟動時打開到同一頁面。您不應該將此商店用于大量數據或復雜數據類型。

要使用iCloud鍵值存儲,請執行以下操作:

在Xcode中,為您的應用配置com.apple.developer.ubiquity-kvstore-identifier權限。
在您的代碼中,創建共享的NSUbiquitousKeyValueStore對象并注冊更改通知。
使用NSUbiquitousKeyValueStore的方法來獲取和設置值。
iCloud中的鍵值數據僅限于簡單的屬性列表類型(字符串,數字,日期等)。

使用iCloud Key-Value Store的策略

鍵值存儲不用于存儲大量數據。它用于存儲配置數據,首選項和少量應用程序相關數據。為了幫助您確定鍵值存儲是否適合您的需要,請考慮以下事項:

每個應用程序在鍵值存儲區中的總空間限制為1 MB。 (還有一個單獨的每鍵限制為1 MB,最多允許1024個鍵。)因此,您不能使用鍵值存儲來共享大量數據。
鍵值存儲僅支持屬性列表類型。屬性列表類型包括簡單類型,如NSNumber,NSString和NSDate對象。您還可以將原始數據塊存儲在NSData對象中,并使用NSArray和NSDictionary對象排列所有類型。
鍵值存儲用于存儲不經常更改的數據。如果設備上的應用程序頻繁更改密鑰值存儲,則系統可能會延遲某些更改的同步,以便最小化到服務器的往返次數。應用程序更頻繁地進行更改,更有可能后來的更改將被延遲,而不會立即顯示在其他設備上。
鍵值存儲不是替換用于保存相同數據的首選項或其他本地技術。鍵值存儲的目的是在應用程序之間共享數據,但如果iCloud未啟用或在給定設備上不可用,則仍然可能需要保留本地數據副本。
如果您使用鍵值存儲來共享首選項,則一種方法是將實際值存儲在用戶默認數據庫中,并使用鍵值存儲進行同步。 (如果不想使用首選項系統,還可以將更改保存在自定義屬性列表文件或其他本地存儲中。)在本地更改密鑰值時,將該更改寫入用戶默認值數據庫和iCloud鍵值存儲在同一時間。要從外部來源接收更改,請為通知NSUbiquitousKeyValueStoreDidChangeExternalNotification添加觀察器,并使用您的處理程序方法來檢測哪些鍵在外部更改,并更新用戶默認數據庫中的相應數據。通過這樣做,您的用戶默認數據庫始終包含正確的配置值。 iCloud鍵值存儲只是確保用戶默認數據庫具有最新更改的機制。

配置您的應用程序以使用鍵值存儲

為了使用鍵值存儲,必須使用com.apple.developer.ubiquity-kvstore-identifier授權顯式配置應用程序。您可以使用Xcode啟用此權限,并為應用程序指定其值,如“應用程序發布指南”中添加iCloud支持中所述。

當您啟用鍵值存儲時,Xcode將自動填充基于應用程序的捆綁包標識符的容器字段的默認值。對于大多數應用,默認值是您想要的。但是,如果您的應用程序與另一個應用程序共享其鍵值存儲空間,則必須指定其他應用程序的軟件包標識符。例如,如果您有一個應用程序的精簡版本,您可能希望它使用與付費版本相同的鍵值存儲。

啟用權限是使用共享的NSUbiquitousKeyValueStore對象所必需的。只要配置權限并包含有效值,密鑰值存儲對象將其數據寫入用戶的iCloud帳戶中的相應位置。如果附加到指定的iCloud容器有問題,任何嘗試讀取或寫入鍵值將失敗。為了確保鍵值存儲配置正確可訪問,您應該在應用程序的啟動周期早期執行類似于以下代碼:

NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
[[NSNotificationCenter defaultCenter] addObserver:self
          selector:@selector(updateKVStoreItems:)
          name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
          object:store];
[store synchronize];

建議您在應用程序啟動周期的早期創建鍵值存儲對象,因為它可以確保您的應用程序及時從iCloud接收更新。確定對鍵和值進行更改的最佳方法是注冊通知NSUbiquitousKeyValueStoreDidChangeExternalNotification。在啟動時,您應該手動調用synchronized方法來檢測是否從外部進行了任何更改。在應用程序執行期間,您無需在其他時間調用該方法。

有關如何配置iOS應用程序的權利的詳細信息,請參閱在App Distribution Guide中添加功能。

訪問鍵值存儲中的值

您可以使用NSUbiquitousKeyValueStore類的方法獲取并設置鍵值存儲值。此類具有獲取和設置類型為Boolean,long long和double的標量值的首選項的方法。它還具有獲取和設置值為NSData,NSDate,NSString,NSNumber,NSArray或NSDictionary對象的鍵的方法。

如果您使用鍵值存儲作為更新本地存儲的首選項的方式,則可以使用與清單3-1相似的代碼來協調用戶默認數據庫的更新。此示例假定您在iCloud和用戶默認數據庫中使用相同的鍵名稱和相應的值。它還假定您以前注冊了updateKVStoreItems:方法作為響應通知NSUbiquitousKeyValueStoreDidChangeExternalNotification的方法。

清單3-1使用iCloud更新本地偏好值

- (void)updateKVStoreItems:(NSNotification*)notification {
   // Get the list of keys that changed.
   NSDictionary* userInfo = [notification userInfo];
   NSNumber* reasonForChange = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey];
   NSInteger reason = -1;

   // If a reason could not be determined, do not update anything.
   if (!reasonForChange)
      return;

   // Update only for changes from the server.
   reason = [reasonForChange integerValue];
   if ((reason == NSUbiquitousKeyValueStoreServerChange) ||
         (reason == NSUbiquitousKeyValueStoreInitialSyncChange)) {
      // If something is changing externally, get the changes
      // and update the corresponding keys locally.
      NSArray* changedKeys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey];
      NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
      NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];

      // This loop assumes you are using the same key names in both
      // the user defaults database and the iCloud key-value store
      for (NSString* key in changedKeys) {
         id value = [store objectForKey:key];
         [userDefaults setObject:value forKey:key];
      }
   }
}

定義關鍵價值商店變更的范圍

對NSUbiquitousKeyValueStore方法之一的每次調用都被視為一個單一的原子事務。將該事務的數據傳輸到iCloud時,整個事務將失敗或成功。如果成功,所有的密鑰都被寫入存儲,如果沒有寫入密鑰,則它們將失敗。商店沒有部分寫鑰匙。發生故障時,系統還會生成包含失敗原因的NSUbiquitousKeyValueStoreDidChangeExternalNotification通知。如果您正在使用鍵值存儲,則應使用該通知來檢測可能出現的問題。

如果您有一組鍵值必須同時更新,才能生效,請將它們一起存儲在一個事務中。要在單個事務中寫入多個鍵和值,請創建具有所有鍵和值的NSDictionary對象。然后使用setDictionary:forKey:方法將字典對象寫入鍵值存儲。編寫整個變更字典可確保所有的鍵都被寫入,或者沒有一個。

實施iOS設置軟件包

在iOS中,Foundation框架提供了存儲偏好數據的低級機制。應用程序有兩個選項可用于顯示首選項:

顯示應用程式內的偏好設定
使用“設置”軟件包可以從“設置”應用程序管理首選項。
您選擇哪個選項取決于用戶如何與首選項進行交互。 “設置”包通常是顯示首選項的首選機制。但是,包含配置選項或其他頻繁訪問的首選項的游戲和其他應用程序可能希望將其顯示在應用程序內。無論您如何呈現它們,您都可以使用NSUserDefaults類來訪問代碼中的偏好值。

本章重點介紹為您的應用創建一個“設置”包。 “設置”包包含描述您的首選項的結構和演示樣式的文件。 “設置”應用程序使用此信息為應用程序創建一個條目,并顯示自定義首選項頁面。

有關如何管理和呈現設置和配置選項的指導,請參閱iOS人機界面指南。

設置應用界面

“設置”應用程序實現一組分層的頁面,用于導航應用程序首選項。 “設置”應用的主頁面列出了可以自定義其首選項的系統和第三方應用程序。選擇第三方應用程序會將用戶置于該應用的首選項。

每個具有“設置”包的應用程序至少有一頁首選項,稱為主頁面。如果你的應用程序只有幾個首選項,主頁面可能是唯一需要的。但是,如果首選項數量太大而不適合主頁,則可以創建鏈接主頁面或其他子頁面的子頁面。您可以創建的子頁面數量沒有特定的限制,但是您應該努力使您的首選項盡可能簡單和易于導航。

每個頁面的內容由您配置的一個或多個控件組成。表4-1列出了“設置”應用程序支持的控件類型,并介紹了如何使用每種類型。該表還列出了存儲在“設置”包的配置文件中的原始密鑰名稱。

表4-1偏好控制類型

控制類型
描述
文本域
文本字段類型顯示標題(可選)和可編輯的文本字段。您可以將此類型用于需要用戶指定自定義字符串值的首選項。
這種類型的鍵是PSTextFieldSpecifier。
標題
標題類型顯示只讀字符串值。您可以使用此類型顯示只讀首選項值。 (如果偏好包含隱藏或非直觀的值,則此類型可以將可能的值映射到自定義字符串。)
這種類型的鍵是PSTitleValueSpecifier。
撥動開關
撥動開關類型顯示ON / OFF開關按鈕。您可以使用此類型配置只能有兩個值之一的首選項。雖然您通常使用此類型來表示包含布爾值的首選項,但您也可以使用包含非布爾值的首選項。
此類型的鍵是PSToggleSwitchSpecifier。
滑塊
滑塊類型顯示滑塊控件。您可以使用此類型表示一系列值的首選項。此類型的值是您指定的最小值和最大值的實數。
這種類型的關鍵是PSSliderSpecifier。
多值
多值類型允許用戶從值列表中選擇一個值。您可以將此類型用于支持一組互斥值的首選項。值可以是任何類型。
此類型的關鍵是PSMultiValueSpecifier。

組類型用于在單個頁面上組織偏好組。組類型不表示可配置的首選項。它只包含在一個或多個可配置首選項之前顯示的標題字符串。
這種類型的關鍵是PSGroupSpecifier。
兒童窗格
子窗格類型允許用戶導航到新頁面的首選項。您可以使用此類型實現分層首選項。有關如何配置和使用此首選項類型的更多信息,請參閱分層首選項。
這種類型的關鍵是PSChildPaneSpecifier。

有關每種首選項類型格式的詳細信息,請參閱“設置應用程序架構參考”。 要了解如何創建和編輯設置頁面文件,請參閱創建和修改設置包。

設置包

“設置”包的名稱為Settings.bundle,位于應用程序捆綁包的頂級目錄中。 此軟件包包含一個或多個描述偏好設置頁面的“設置”頁面文件。 它還可能包括顯示您的首選項所需的其他支持文件,例如圖像或本地化字符串。 典型的“設置”包的內容如表4-2所示。

表4-2 Settings.bundle目錄的內容

項目名
描述
Root.plist
“設置”頁面文件包含根頁面的首選項。該文件的名稱必須是Root.plist。該文件的內容在“設置頁面文件格式”中有更詳細的描述。
其他.plist文件
如果您使用子窗格構建一組分層首選項,則每個子窗格的內容將存儲在單獨的“設置”頁面文件中。您負責命名這些文件并將其與正確的子窗格相關聯。
一個或多個.lproj目錄
這些目錄為“設置”頁面文件存儲本地化的字符串資源每個目錄包含單個字符串文件,其標題在“設置”頁面文件中指定。字符串文件提供本地化字符串以顯示您的首選項。
其他圖像
如果使用滑塊控件,則可以將滑塊的圖像存儲在軟件包的頂級目錄中。
除了設置包之外,應用包可以包含應用設置的自定義圖標。 “設置”應用程序會在應用程序首選項的條目旁邊顯示您提供的圖標。有關應用程序圖標的信息以及如何指定它們,請參閱“iOS編程指南”。

當設置應用啟動時,它會檢查每個自定義應用程序是否存在“設置”包。對于找到的每個自定義捆綁包,它加載該捆綁包,并在“設置”主頁面中顯示相應的應用程序的名稱和圖標。當用戶點擊屬于您的應用程序的行時,“設置”將加載“設置”包的Root.plist設置頁面文件,并使用該文件構建應用程序的首選項。

除了加載您的軟件包的Root.plist設置頁面文件之外,“設置”應用程序還會根據需要加載該文件的任何特定于語言的資源。每個“設置”頁面文件都可以包含一個關聯的.strings文件,其中包含任何用戶可見字符串的本地化值。當您準備顯示的偏好設置時,“設置”應用程序會以用戶首選語言查找字符串資源,并在顯示之前將其替換為您的首選項頁面。

設置頁面文件格式
每個“設置”頁面文件都以iPhone設置屬性列表文件格式存儲,這是一種結構化文件格式。編輯“設置”頁面文件的最簡單的方法是使用Xcode的內置編輯器設施;請參閱準備設置頁面進行編輯。您還可以使用Xcode工具附帶的“屬性列表編輯器”應用程序編輯屬性列表文件。

注意:在構建應用程序時,Xcode會將您項目中的任何基于XML的屬性文件轉換為二進制格式。此轉換可以節省空間,并為您自動完成。
每個“設置”頁面文件的根元素包含表4-3中列出的鍵。實際上只需要一個鍵,但建議您包含這兩個鍵。

表4-3首選項的根級別鍵設置頁面文件

類型

首選項(必需)
排列
該鍵的值是一個字典數組,每個字典包含單個控件的信息。有關控制類型的列表,請參見表4-1。有關與每個控件相關聯的鍵的說明,請參閱設置應用程序架構參考。
StringsTable

與此文件關聯的字符串文件的名稱。該文件的副本(具有適當的本地化字符串)應位于每個包的特定于語言的項目目錄中。如果不包含此鍵,則該文件中的字符串不會本地化。有關如何使用這些字符串的信息,請參閱本地化資源。
層次偏好
如果您打算分層組織您的首選項,則您定義的每個頁面都必須有自己獨立的.plist文件。每個.plist文件都包含僅在該頁面上顯示的一組首選項。您的應用程序的主要首選項頁面始終存儲在名為Root.plist的文件中。額外的頁面可以給你任何你喜歡的名字。

要指定父頁面和子頁面之間的鏈接,您需要在父頁面中包含子窗格控件。子窗格控件創建一個行,當點擊時,會顯示一個新的設置頁面。子窗格控件的“文件”鍵標識帶有子頁面內容的.plist文件的名稱。標題鍵標識子頁面的標題;此標題也用作用于顯示子頁面的控件的文本。 “設置”應用程序自動提供子頁面上的導航控件,以允許用戶返回到父頁面。

圖4-1顯示了這種分層的頁面集合是如何工作的。該圖的左側顯示.plist文件,右側顯示相應頁面之間的關系。

圖4-1使用子窗格組織首選項

有關子窗格控件及其關聯鍵的詳細信息,請參閱設置應用程序架構參考。

本地化資源
因為首選項包含用戶可見的字符串,所以您應該使用設置包提供這些字符串的本地化版本。每個首選項可以為您的捆綁包支持的每個本地區擁有一個關聯的.strings文件。當“設置”應用程序遇到支持本地化的密鑰時,它會檢查適當本地化的.strings文件以獲取匹配的密鑰。如果找到一個,它將顯示與該關鍵字關聯的值。

在查找.strings文件等本地化資源時,“設置”應用程序遵循與其他iOS應用程序相同的規則。它首先嘗試查找與用戶首選語言設置匹配的資源的本地化版本。如果沒有這樣的資源,則選擇適當的后備語言。

有關字符串文件格式,特定于語言的項目目錄以及從捆綁包中檢索特定語言資源的信息,請參閱“國際化和本地化指南”。

創建和修改設置包

Xcode提供了一個模板,用于將當前項目添加到“設置”包中。默認的“設置”包包含一個Root.plist文件和用于存儲任何本地化資源的默認語言目錄。您可以根據需要擴展此捆綁包,以包含“設置”包所需的其他屬性列表文件和資源。

添加設置包
要將設置包添加到您的Xcode項目中:

選擇文件>新建>新建文件。
在iOS下,選擇資源,然后選擇設置包模板。
將文件命名為Settings.bundle。
除了向項目添加新的“設置”包之外,Xcode還會將該捆綁包添加到應用程序目標的“復制捆綁資源”構建階段。因此,您只需修改“設置”包的屬性列表文件,并添加任何所需的資源。

新的“設置”包具有以下結構:

Settings.bundle/
Root.plist
en.lproj/
Root.strings

準備編輯設置頁面
在編輯設置包中的任何屬性列表文件之前,您應該配置Xcode編輯器,以將這些文件的內容格式化為iPhone設置。 Xcode會自動為Root.plist文件執行此操作,但您可能需要手動格式化其他屬性列表文件。 要將文件格式化為iPhone設置,請執行以下操作:

選擇文件。
按住Control鍵并單擊編輯器窗口,如果尚未選擇,請選擇“屬性列表類型”>“iPhone設置”。
格式化屬性列表可以更容易地理解和編輯文件的內容。 Xcode代替適合所選格式的人類可讀字符串(如圖4-2所示)。

圖4-2 Root.plist文件的格式化內容

配置設置頁面:教程
本節介紹如何配置“設置”頁面以顯示所需的控件。 本教程的目標是創建一個如圖4-3所示的頁面。 如果尚未為項目創建“設置”包,則應按照添加設置包中的說明進行操作,然后再繼續執行這些步驟。

圖4-3“根設置”頁面

打開“首選項”鍵以顯示模板附帶的默認項。
將項目0的標題更改為聲音。
披露優先項目0。
將“標題”鍵的值從“組”更改為“聲音”。
將“類型”鍵設置為“組”。
單擊項目的公開三角形以隱藏其內容。
為重命名的Sound組創建第一個切換開關。
選擇首選項目的項目2(切換開關項目),然后選擇編輯>剪切。
選擇項目0,然后選擇編輯>粘貼。 (這將移動切換開關項目在文本字段項目前面。)
打開切換開關項目以顯示其配置鍵。
將標題鍵的值更改為播放聲音。
將Identifier鍵的值更改為play_sounds_preference。
單擊項目的公開三角形以隱藏其內容。
為“聲音”組創建第二個撥動開關。
選擇項目1(播放聲音切換開關)。
選擇編輯>復制。
選擇“編輯”>“粘貼”,將第一個切換開關的副本放在第一個。
打開新的切換開關項目以顯示其配置鍵。
將其標題鍵的值更改為3D Sound。
將其Identifier鍵的值更改為3D_sound_preference。
單擊項目的公開三角形以隱藏其內容。
此時,您已完成第一組設置,并可以創建用戶信息組。
將項目3更改為組控件,并將其命名為用戶信息。
單擊首選項中的項目3。這將顯示一個包含項目類型列表的彈出式菜單。
從彈出菜單中,選擇組以更改控件的類型。
披露項目3的內容。
將“標題”鍵的值設置為“用戶信息”。
單擊項目的公開三角形以隱藏其內容。
創建名稱字段。
在首選項中選擇項目4。
使用彈出菜單將其類型更改為文本字段。
將“標題”鍵的值設置為“名稱”。
將Identifier鍵的值設置為user_name。
單擊項目的公開三角形以隱藏其內容。
創建體驗級設置。
選擇項目4。
按住Control鍵并單擊編輯器窗口,然后選擇添加行添加新項目。
將新項目的類型設置為多值。
披露項目的內容,并將其標題設置為體驗級別,其標識符為experience_preference,其默認值為0。
選擇“默認值”鍵后,按住Control鍵并單擊并添加行添加標題數組。
選擇“標題”數組,然后按“返回”添加新的子項。
再添加兩個子項,共創建三個項目。
將子項的值設置為“初學者”,“專家”和“主”。
隱藏密鑰的子項。
為Values數組添加一個新項目。
將三個子項添加到Values數組,并將其值設置為0,1和2。
隱藏項目5的內容。
將最后一個組添加到您的設置頁面。
創建一個新項目并將其類型設置為“組”,并將其標題設置為“重力”。
創建另一個新項目并將其類型設置為Slider,其標識符為gravity_preference,其默認值為1,其最大值設置為2。

創建其他設置頁面文件
設置包模板包括Root.plist文件,它定義了您的應用程序的頂部“設置”頁面。要定義其他“設置”頁面,您必須將其他屬性列表文件添加到“設置”包中。

要將屬性列表文件添加到Xcode中的“設置”包中,請執行以下操作:

選擇文件>新建>新建文件。
在iOS下,選擇資源,然后選擇屬性列表模板。
選擇新文件以在編輯器中顯示其內容。
按住Control鍵并單擊編輯器窗格,然后選擇“屬性列表類型”>“iPhone設置”,以格式化內容。
按住Control鍵再次單擊編輯器窗格,然后選擇添加行添加新的鍵。
添加和配置您需要的任何其他鍵。
將新的“設置”頁面添加到“設置”包后,可以按照“配置設置頁面:教程”中所述編輯頁面的內容。要顯示頁面的設置,您必須從子窗格控件中引用它,如“分層首選項”中所述。

注意:在Xcode 4中,向項目添加屬性列表文件不會自動將其與您的“設置”包相關聯。您必須使用Finder將任何其他屬性列表文件移動到“設置”包中。
模擬應用程序的調試首選項

運行應用程序時,iOS Simulator會將您應用程序的任何首選項存儲在?/ Library / Application Support / iOS Simulator / User / Applications / <APP_ID> / Library / Preferences中,其中<APP_ID>是iOS使用的以編程方式生成的目錄名識別您的應用程序

每次構建應用程序時,Xcode會保留您的應用程序首選項和其他相關的庫文件。如果要刪除當前的首選項進行測試,可以從Simulator中刪除應用程序,或從“iOS模擬器”菜單中選擇“重置內容和設置”。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容