在上一节中,我们通过探讨应用的系统设置的基本功能,了解运用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 ,代码如下:

 #import "ViewController.h"
#import "settingHead.h" @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
[self refreshValue];
} -(void)refreshValue
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.label1.text = [defaults objectForKey:Officer];
self.label2.text = [defaults objectForKey:AuthorizationCode];
self.label3.text = [defaults objectForKey:Rank];
self.label4.text = [defaults boolForKey:IsWarp]?@"Enable":@"Disable";
self.label5.text = [[defaults objectForKey:SliderValue] stringValue]; self.enginesSwitch.on = [defaults boolForKey:IsWarp];
self.WarpSlider.value = [defaults floatForKey:SliderValue];
}

在以上的refreshValue方法,首先通过调用NSUserDefaults类获取了标准用户默认设置,然后调用objectForKey方法访问获取对应键值的内容、

需要注意的是label1到label5,除了label4外,都是以NSString对象的形式返回,label4中defaults调用键值为IsWarp的方法返回的是bool值。因此我们得到结果后给予判断再赋值给label4的文本;

而label5由于是内容为滑块的值,是以NSNumber形式返回的,因此需要调用改对象的stringValue方法来获取它存储的值的字符串表示。

二、在应用中修改用户默认设置

应用中修改用户默认设置所调用的方法为:“setObject forKey: ”,在在ViewController.m中,需要在关联的开关滑块方法WarpSliderBtn、enginesSwitchBtn中添加如下代码:

 - (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];
}

运行、我们可以看到如下界面:

【图3  】

我们可以看到,即使我们为Multi Value、IsWarp设置默认值得,依然不会显示在我们的应用中,这是因为:我们的应用完全不知道设置捆绑包中已保存的该应用的偏好设置,即使我们在设置中设置好相应的值,然后再运行一次可以看到应用上显示值,但是当我们删除掉运用再运行一次,还是显示为空值,而不能看到默认值。

我们可以作如下处理:如果我们尝试查找未设置的键/值,但该键至少会有一个默认值,可以用registerDefaults:方法,为了使得改设置在整个运用中都能有效,最好在应用启动时就调用它

因此,点击AppDelegate.m文件,添加"settingHead.h”头文件,然后在didFinishLaunchingWithOptions中键入以下代码:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch. NSDictionary *dict = @{@"warp":@YES,
@"warpFactor":@,
};
[[NSUserDefaults standardUserDefaults] registerDefaults:dict];
return YES;
}

按下command+shift+H ,在ios模拟器主页上面长按我们创建的app,删除它,然后按下command+R再运行一次我们可以看到刚刚我们通过registerDefaults:方法设置的默认值。

三、同步系统设置与应用上的数据

现在我们可以尝试下通过调整应用来修改系统设置的值,但是奇怪的是:当我们修改系统设置,再打开app应用上面的数据也没有变化,当我们修改app上面的滑块与开关,再查看系统设置也是没有变化。

这也是iOS系统的一个特点:当应用在运行时返回主屏幕,并不会退出应用,而是由操作系统在后台将其暂停了,这样它就可以随时能够快速启动,因为用户在切换应用时,重新唤醒一个应用比重新启动一个应用要省下很多时间,这使得iOS系统下应用的切换更加高效快捷。这也是后台应用的基本知识。

那么在这个例子中,我们应该如何同步更新数据呢,其实只要在唤醒的时候添加一个功能:重新加载同步用户偏好设置并重新显示它们的内容。

接下来我们需要运用到“通知”这一个对象之间进行通信的轻量级机制。通知中心是一个单例对象,作用是在对象之间传送通知。“通知”通常是在某些事件发生时发送的说明,UIApplicaton类会发送大量的通知(可以从Xcode的文档阅读器中找到这些更加详细的内容,在UIApplicaton页面的底部)。

应用在回到前台时,刷新一下它显示的内容,因此我们需要调用名为 “UIApplicationWillEnterForegroundNotification”的通知,编写viewWillAppear:方法时,我们会订阅该通知,并告诉通知中心该通知出现时需要调用的方法,这个方法我们可以命名为:“applicationwillenterforegound”、

点击ViewController.m,添加以下代码:

 -(void)applicationwillenterforegound:(NSNotification *)notification
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//进行应用设置与控件上的数据同步
[defaults synchronize];
[self refreshValue];
}

其中,我们可以看到defaults调用synchronize方法,该方法强制用户默认值保存尚未保存的修改,然后从存储中重新加载所有未修改的偏好设置。事实上,这是在强制它重新读取已保存的偏好设置,从而获取设置应用中所作的修改,然后调用refreshValue:方法来个更新显示的内容。

Now,我们需要在ViewController.m中实现viewWillAppear:方法,使得该控制器订阅我们关注的“UIApplicationWillEnterForegroundNotification”通知。如下:

 -(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//注册观测者
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationwillenterforegound:) name:UIApplicationWillEnterForegroundNotification object:app];
}

在该addObserver:  selectornameobject: 方法中,

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中撤销注册,因此我们可以添加代码如下:

-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
/*
注销监听 也可以用removeObserver:self name: object:方法来撤销对特定通知的订阅,但以下这种更加方便:直接告知确保通知中心彻底忘记我们的observer的方法,不管注册它是为了 接收多少种通知。
*/
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

按下“command+R”运行。在应用的空间【参照图1】以及系统设置上面编辑,以及切换时查看同步效果。

做完以上工作,我们已经可以了解了设置应用和用户默认机制的基本概念,懂得如何添加捆绑包、为应用的偏好设置构建结构化的视图、通过NSUserDedeults读写偏好设置以及修改设置等内容,并且开发了相关的项目。相信在iOS开发的工作学习你一定也会用到相关的技术,并不断完善。

iOS开发--应用设置及用户默认设置【2、读取应用中的设置】的更多相关文章

  1. iOS开发--应用设置及用户默认设置【1、bundle的运用】

           在iphone里面,应用都会在“设置”里面有个专属的应用设置,选择该菜单界面,用户便可以在其中输入和更改各种选项,协助用户更便捷设置个人喜好与习惯. 在这一节中,希望能通过对捆绑包(bu ...

  2. iOS开发--应用设置及用户默认设置——转载

    [链接]iOS开发--应用设置及用户默认设置[1.bundlehttp://www.jianshu.com/p/6f2913f6b218 在iphone里面,应用都会在“设置”里面有个专属的应用设置, ...

  3. iOS开发之线程间的MachPort通信与子线程中的Notification转发

    如题,今天的博客我们就来记录一下iOS开发中使用MachPort来实现线程间的通信,然后使用该知识点来转发子线程中所发出的Notification.简单的说,MachPort的工作方式其实是将NSMa ...

  4. ios开发总结,日常开发:ios开发功能收集,经验分享等等(不断更新中。。。)

    github资料学习和下载地址:https://github.com/niexiaobo/MyDailyDevelopmentNotes ios 学习模块 ios APP 日志管理的重要性: 一个功能 ...

  5. iOS开发之如何在用户删除应用后保持一些数据

    在开发过程中我们有时候在用户删除时候保存一些信息在用户下次安装应用时候使用,这个时候我们可以使用剪切版UIPasteboard的FindUIPasteboard和钥匙串keychain的使用 剪切版剪 ...

  6. iOS开发 首次启动显示用户引导,第二次启动直接进入App,UIScrollView,UIPageControl,NSUserDefaults

    首先创建一个引导图的控制器类 UserGuideViewController.h和UserGuideViewController.m #import <UIKit/UIKit.h> #im ...

  7. iOS开发手记 - iOS9.3 UINavigationController添加后不显示storyboard中viewcontroller里的控件的解决方法

    我原先是这么做的,通常也是这么做 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSD ...

  8. android,在java代码中,如何给textview设置不同的颜色,以及引用color中资源设置颜色

    textV.setTextColor(Color.parseColor("#FF0000")); <pre name="code" class=" ...

  9. webstorm 10 设置文件的默认编码

    我在使用webstorm时,发现文件的默认编码是GBK 然后我找到了点击此处可以修改这个文件的编码,但是以后新建文件和项目默认生成的文件还是GBK, 设置项目文件的默认编码可以在 File----Se ...

随机推荐

  1. linux kernel tainted

    日志中会有一些信息: dmesg | grep -i tainted 具体代码可以通过proc看到: cat /proc/sys/kernel/tainted 数字的意义: tainted: Non- ...

  2. 关于relative和absolute的总结

    对于定位这个性质我原理上来说自己是明白的,但是在实践的过程中,总会出现各种稀奇古怪的情况,加relative或是absolute就可以解决,但是遇到这些情况总是不明白为什么!!!难道是脑容量太小的原因 ...

  3. [GodLove]Wine93 Tarining Round #2

    比赛链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=44704#overview 题目来源: ZOJ Monthly, June 2 ...

  4. 关于路径的使用,assi下载和

    直接给一个路径下载图片,这函数直接使用assi -(void)downloadWithURL:(NSString*)RequestUrl SavePath:(NSString*)savepath wi ...

  5. Linux TC基于CBQ队列的流量管理范例

    参考了TC的很多文档,自己也整理了一篇配置记录.在实际使用过程中效果还不错,在此分享给大家以备参考.环境:局域网规模不是很大40多台机器. NAT共享上网(内网:eth0 外网:eth2)CBQ是通过 ...

  6. jQuery plugin: Autocomplete 参数及实例

    官网:jQuery plugin: Autocomplete          (注:此插件已经不再更新.它的继任者是jQuery UI的一部分,) 此插件依赖于 jquery 1.2.6 --- j ...

  7. [翻译]Understanding Weak References(理解弱引用)

    原文 Understanding Weak References Posted by enicholas on May 4, 2006 at 5:06 PM PDT 译文 我面试的这几个人怎么这么渣啊 ...

  8. bootstrap-4

    html文档中,列表结构主要有三种:有序列表.无序列表和定义列表:<ul><li>.<ol><li>.<dl><dt><d ...

  9. 10、java中的抽象类

    当多个类中出现相同功能,但是功能主体不同,这是可以进行向上抽取.这时,只抽取功能定义,而不抽取功能主体. 抽象:看不懂. 抽象类的特点:1,抽象方法一定在抽象类中.2,抽象方法和抽象类都必须被abst ...

  10. bzoj3087: Coci2009 misolovke

    Description [misolovke]给定一个 N*N 的网格.每个格子里至少会有一个捕鼠器, 并且已知每个格子里的捕鼠器个数.现在需要在 每一行 中选取恰好 K 个连续的格子, 把里面的捕鼠 ...