在上一節中,我們通過探討應用的系統設置的基本功能,瞭解運用bundle捆綁包以及plist文件的基本開發。用戶能夠使用設置應用來聲明他們的偏好設置,那麼我們怎樣去調用用戶所設置的參數呢,上節我們只創建了Setting.bundle捆綁包,在這個基礎上,這一節,我們將繼續討論,關於如何讀取應用中...
在上一節中,我們通過探討應用的系統設置的基本功能,瞭解運用bundle捆綁包以及plist文件的基本開發。用戶能夠使用設置應用來聲明他們的偏好設置,那麼我們怎樣去調用用戶所設置的參數呢,上節我們只創建了Setting.bundle捆綁包,在這個基礎上,這一節,我們將繼續討論,關於如何讀取應用中的設置,以及讓app應用與設置的數據同步。
我們將通過本節內容達到的效果如下:
【圖1 app應用界面】
【本次開發環境: Xcode:7.2 iOS Simulator:iphone6S plus By:啊左】
一、獲取用戶設置
1、NSUserDefaults類的介紹
訪問用戶的設置需要調用NSUserDefaults類,NSUserDefaults為單例類,需要調用類方法standardUserDefaults來獲取指向標準用戶預設設置的指針:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
defaults可以像NSDictionary類一樣進方法的調用,例如“objectForKey:”,會返回一個Object-C對象,如NSString、NSDate、NSNumber。若需要獲取整型、浮點型等方式,可以用“intForKey:”、“floatForKey”、“boolForKey”等其他方法。
2、鍵值
在上一節中,plist屬性列表中的偏好設置欄位,每個條目都有特定的鍵,例如Item1對應的是“officer”、滑塊Item6對應的是“SliderValue”,這些鍵都是做為調用該項的ID。
因此我們可以先把這些鍵放在自己創建的頭文件"settingHead.h"中,便於調用。內容如下:
#ifndef settingHead_h #define settingHead_h #define Officer @"officer" #define AuthorizationCode @"authorizationCode" #define Rank @"rank" #define IsWarp @"IsWarp" #define SliderValue @"SliderValue" #define moreFactor @"MoresliderValue" #endif /* settingHead_h */
3、關聯相關控制項
接下來,我們使用Main.storyboard創建14個label、一個開關、一個滑塊,為左邊8個label修改為Officer、code等內容如下:
【圖2 Main.storyboard設置界面】
確認該視圖關聯的是ViewController,然後打開輔助編輯器(或者在Main.storyboard界面按下option+command+return),按住control鍵分別從Main.storyboard圖標拖動到ViewController.h中,為右邊6個label以及滑塊、開關添加在ViewController.h的介面,代碼如下:
#import <UIKit/UIKit.h> @interface ViewController : UIViewController //5個label介面 @property (weak, nonatomic) IBOutlet UILabel *label1; @property (weak, nonatomic) IBOutlet UILabel *label2; @property (weak, nonatomic) IBOutlet UILabel *label3; @property (weak, nonatomic) IBOutlet UILabel *label4; @property (weak, nonatomic) IBOutlet UILabel *label5; //滑塊、開關介面 @property (weak, nonatomic) IBOutlet UISwitch *enginesSwitch; @property (weak, nonatomic) IBOutlet UISlider *WarpSlider; //滑塊、開關的介面方法(修改用戶預設設置) - (IBAction)enginesSwitchBtn:(UISwitch *)sender; - (IBAction)WarpSliderBtn:(UISlider *)sender; @end
在ViewController.m中,敲入: #import "settingHead.h" 添加鍵集合的頭文件,然後添加一個更新app界面數據的方法: -(void)refreshValue ,代碼如下:
1 #import "ViewController.h" 2 #import "settingHead.h" 3 4 @implementation ViewController 5 6 - (void)viewDidLoad { 7 [super viewDidLoad]; 8 self.view.backgroundColor = [UIColor orangeColor]; 9 [self refreshValue]; 10 } 11 12 -(void)refreshValue 13 { 14 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 15 self.label1.text = [defaults objectForKey:Officer]; 16 self.label2.text = [defaults objectForKey:AuthorizationCode]; 17 self.label3.text = [defaults objectForKey:Rank]; 18 self.label4.text = [defaults boolForKey:IsWarp]?@"Enable":@"Disable"; 19 self.label5.text = [[defaults objectForKey:SliderValue] stringValue]; 20 21 self.enginesSwitch.on = [defaults boolForKey:IsWarp]; 22 self.WarpSlider.value = [defaults floatForKey:SliderValue]; 23 }
在以上的refreshValue方法,首先通過調用NSUserDefaults類獲取了標準用戶預設設置,然後調用objectForKey方法訪問獲取對應鍵值的內容、
需要註意的是label1到label5,除了label4外,都是以NSString對象的形式返回,label4中defaults調用鍵值為IsWarp的方法返回的是bool值。因此我們得到結果後給予判斷再賦值給label4的文本;
而label5由於是內容為滑塊的值,是以NSNumber形式返回的,因此需要調用改對象的stringValue方法來獲取它存儲的值的字元串表示。
二、在應用中修改用戶預設設置
應用中修改用戶預設設置所調用的方法為:“setObject forKey: ”,在在ViewController.m中,需要在關聯的開關滑塊方法WarpSliderBtn、enginesSwitchBtn中添加如下代碼:
1 - (IBAction)WarpSliderBtn:(UISlider *)sender { 2 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 3 [defaults setFloat:self.WarpSlider.value forKey:SliderValue]; 4 [defaults synchronize]; 5 } 6 - (IBAction)enginesSwitchBtn:(UISwitch *)sender { 7 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 8 [defaults setBool:self.enginesSwitch.on forKey:IsWarp]; 9 [defaults synchronize]; 10 }
運行、我們可以看到如下界面:
【圖3 】
我們可以看到,即使我們為Multi Value、IsWarp設置預設值得,依然不會顯示在我們的應用中,這是因為:我們的應用完全不知道設置捆綁包中已保存的該應用的偏好設置,即使我們在設置中設置好相應的值,然後再運行一次可以看到應用上顯示值,但是當我們刪除掉運用再運行一次,還是顯示為空值,而不能看到預設值。
我們可以作如下處理:如果我們嘗試查找未設置的鍵/值,但該鍵至少會有一個預設值,可以用registerDefaults:方法,為了使得改設置在整個運用中都能有效,最好在應用啟動時就調用它
因此,點擊AppDelegate.m文件,添加"settingHead.h”頭文件,然後在didFinishLaunchingWithOptions中鍵入以下代碼:
1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 2 // Override point for customization after application launch. 3 4 NSDictionary *dict = @{@"warp":@YES, 5 @"warpFactor":@5, 6 }; 7 [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; 8 return YES; 9 }
按下command+shift+H ,在ios模擬器主頁上面長按我們創建的app,刪除它,然後按下command+R再運行一次我們可以看到剛剛我們通過registerDefaults:方法設置的預設值。
三、同步系統設置與應用上的數據
現在我們可以嘗試下通過調整應用來修改系統設置的值,但是奇怪的是:當我們修改系統設置,再打開app應用上面的數據也沒有變化,當我們修改app上面的滑塊與開關,再查看系統設置也是沒有變化。
這也是ios系統的一個特點:當應用在運行時返回主屏幕,並不會退出應用,而是由操作系統在後臺將其暫停了,這樣它就可以隨時能夠快速啟動,因為用戶在切換應用時,重新喚醒一個應用比從新啟動一個應用要省下很多時間,這使得ios系統下應用的切換更加高效快捷。這也是後臺應用的基本知識。
那麼在這個例子中,我們應該如何同步更新數據呢,其實只要在喚醒的時候添加一個功能:重新載入同步用戶偏好設置並重新顯示它們的內容。
接下來我們需要運用到“通知”這一個對象之間進行通信的輕量級機制。通知中心是一個單例對象,作用是在對象之間傳送通知。“通知”通常是在某些事件發生時發送的說明,UIApplicaton類會發送大量的通知(可以從Xcode的文檔閱讀器中找到這些更加詳細的內容,在UIApplicaton頁面的底部)。
應用在回到前臺時,刷新一下它顯示的內容,因此我們需要調用名為 “UIApplicationWillEnterForegroundNotification”的通知,編寫viewWillAppear:方法時,我們會訂閱該通知,並告訴通知中心該通知出現時需要調用的方法,這個方法我們可以命名為:“applicationwillenterforegound”、
點擊ViewController.m,添加以下代碼:
1 -(void)applicationwillenterforegound:(NSNotification *)notification 2 { 3 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 4 //進行應用設置與控制項上的數據同步 5 [defaults synchronize]; 6 [self refreshValue]; 7 }
其中,我們可以看到defaults調用synchronize方法,該方法強制用戶預設值保存尚未保存的修改,然後從存儲中重新載入所有未修改的偏好設置。事實上,這是在強制它重新讀取已保存的偏好設置,從而獲取設置應用中所作的修改,然後調用refreshValue:方法來個更新顯示的內容。
Now,我們需要在ViewController.m中實現viewWillAppear:方法,使得該控制器訂閱我們關註的“UIApplicationWillEnterForegroundNotification”通知。如下:
1 -(void)viewWillAppear:(BOOL)animated 2 { 3 [super viewWillAppear:animated]; 4 //註冊觀測者 5 UIApplication *app = [UIApplication sharedApplication]; 6 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationwillenterforegound:) name:UIApplicationWillEnterForegroundNotification object:app]; 7 }
在該addObserver: selector: name: object: 方法中,
observer傳遞的是self,也就是我們的控制器本身;
而selector,調用的是我們自己寫的選擇器方法,用於告訴通知中心在該通知發出時調用該方法;
name是我們要接収的通知的名稱,一般可以在Xcode的文檔閱讀器中找到這些更加詳細的內容;
最後一個參數app,是我們關心的獲得通知的來源對象,如果改為nil,表示只要有方法發出“UIApplicationWillEnterForegroundNotification”通知,我們就會得到通知。
這樣,我們就完成了,回到app前臺重新載入內容的開發。
那麼當用戶在應用中操作控制項,又怎樣把內容同步到系統的預設設置裡面呢?很簡單,只要在我們設置的控制項,開關與滑塊的方法中添加一行 “[defaults synchronize]” 即可。
- (IBAction)WarpSliderBtn:(UISlider *)sender { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setFloat:self.WarpSlider.value forKey:SliderValue]; [defaults synchronize]; } - (IBAction)enginesSwitchBtn:(UISwitch *)sender { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:self.enginesSwitch.on forKey:IsWarp]; [defaults synchronize]; }
【註意:調用synchronize:方法的開銷會很大,因為要比較應用以及系統設置中的所有用戶偏好設置,因此應該儘量減少對synchronize的調用,不過像我們此次的項目中,在響應每個用戶操作時調用它一次,並不會造成任何顯著的性能問題。】
當然,為了使得系統的工作過程更加清晰,我們可以在通知系統不需要接收到通知時,在viewDidDisappear中撤銷註冊,因此我們可以添加代碼如下
1 -(void)viewDidDisappear:(BOOL)animated 2 { 3 [super viewDidDisappear:animated]; 4 /* 5 註銷監聽 也可以用removeObserver:self name: object:方法來撤銷對特定通知的訂閱,但以下這種更加方便:直接告知確保通知中心徹底忘記我們的observer的方法,不管註冊它是為了 接收多少種通知。 6 */ 7 [[NSNotificationCenter defaultCenter] removeObserver:self]; 8 }
按下“command+R”運行。在應用的空間【參照圖1】以及系統設置上面編輯,以及切換時查看同步效果。
做完以上工作,我們已經可以瞭解了設置應用和用戶預設機制的基本概念,懂得如何添加捆綁包,如何為應用的偏好設置構建結構化的視圖,通過NSUserDedeults讀寫偏好設置以及修改設置內容,並且開發了相關的項目。
By:啊左~~