从零开始学ios开发(二十):Application Settings and User Defaults(下)

时间:2021-10-01 09:16:17

在上一篇的学习中,我们知道了如何为一个App添加它的Settings设置项,在Settings设置项中我们可以添加哪些类型的控件,这些控件都是通过一个plist来进行管理的,我们只需对plist进行修改添加,就可以映射到Settings中。但是在上一篇中,我们并没有学习Settings和App的交互,在这一篇中我们将进行学习,如何在一个App中读取Settings中的值,如何在App中修改Settings中的值,好了,下面开始我们这次的学习。

1)NSUserDefaults
NSUserDefaults是ios自带的一个对象,它的主要作用对Settings中的变量(我们添加的控件)进行取值和赋值。在上一篇中,我们在创建plist的时候,每一个Item都有一个Key,NSUserDefaults就是根据这个Key来找到对象,然后取得值,或者赋值。这个其实就是一个key-value对,NSUserDefaults在用法上和NSDictionary是一样的,因此它也有很多类似的对象例如:objectForKey,intForKey,floatForKey,boolForKey,这些都很简单。另外NSUserDefaults是一个单例模式(Singleton),也就是说在整个app中只有一个NSUserDefaults对象存在,这样可以避免在2个地方同时对一个Item进行操作的情况,在程序中,我们使用standardUserDefaults方法来取得NSUserDefaults对象:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

2)从Settings中读取值
打开BIDMainViewController.h,添加如下代码

从零开始学ios开发(二十):Application Settings and User Defaults(下)
#import "BIDFlipsideViewController.h"
#define kUsernameKey @"username"
#define kPasswordKey @"password"
#define kProtocolKey @"protocol"
#define kWarpDriveKey @"warp"
#define kWarpFactorKey @"warpFactor"
#define kFavoriteTeaKey @"favoriteTea"
#define kFavoriteCandyKey @"favoriteCandy"
#define kFavoriteGameKey @"favoriteGame"
#define kFavoriteExcuseKey @"favoriteExcuse"
#define kFavoriteSinKey @"favoriteSin"
@interface BIDMainViewController : UIViewController <BIDFlipsideViewControllerDelegate> @property (weak, nonatomic) IBOutlet UILabel *usernameLabel;
@property (weak, nonatomic) IBOutlet UILabel *passwordLabel;
@property (weak, nonatomic) IBOutlet UILabel *protocolLabel;
@property (weak, nonatomic) IBOutlet UILabel *warpDriveLabel;
@property (weak, nonatomic) IBOutlet UILabel *warpFactorLabel;
@property (weak, nonatomic) IBOutlet UILabel *favoriteTeaLabel;
@property (weak, nonatomic) IBOutlet UILabel *favoriteCandyLabel;
@property (weak, nonatomic) IBOutlet UILabel *favoriteGameLabel;
@property (weak, nonatomic) IBOutlet UILabel *favoriteExcuseLabel;
@property (weak, nonatomic) IBOutlet UILabel *favoriteSinLabel; - (void)refreshFields;
@end
从零开始学ios开发(二十):Application Settings and User Defaults(下)

上面的代码定义了10个常量Key,用来在之后的代码中根据Key获取Settings中的值,接着声明10个IBOutlet,且他们都是指向Label的,最后声明了一个refreshField方法,用于从Settings中读取值然后赋给Label。

保存上面的code,然后在Project navigator中选中MainStoryboard.storyboard,在Layout area中会显示2个View,分别是Main View和FlipSide View,我们选中Main View,然后打开Attribute inspector,找到Backgrund,将其背景色变为白色
从零开始学ios开发(二十):Application Settings and User Defaults(下)

在Main View的右下角,有一个Info button(一个圆圈,中间有一个字母i),选中它,然后在Attribute inspector中将其Type改成“Info Dark”
从零开始学ios开发(二十):Application Settings and User Defaults(下)
这样就能够很容易的找到它所在的地方了
从零开始学ios开发(二十):Application Settings and User Defaults(下)

如果你觉得直接在Main View中选择一个白色的Info button很困难,那么你可以打开Main View Controller Scene,在里面你可以方便的找到它
从零开始学ios开发(二十):Application Settings and User Defaults(下)

好,接下来我们就要往Main View中拖控件了,一共拖20个Label,其中十个Label为静态的,仅仅显示文字,另外十个需要与刚才定义的IBOutlet关联起来,用于显示Settings中的值。

根据下图的样子,将Label拖入到Main View中
从零开始学ios开发(二十):Application Settings and User Defaults(下)
排列什么的无所谓,自己喜欢就好,主要是右边的10个Label,他们的宽度都是到最右边出现辅助线的位置,以保证能够最大限度容纳字符。

好了,下面的工作就是关联IBOutlet和view上面的Label了,一共要关联10个Label,选中Main View Controller Scene中的Main View Control,control-drag到Label上(右边的一排Label),在弹出的框中选中相对应的IBOutlet
从零开始学ios开发(二十):Application Settings and User Defaults(下)

好了,保存所有的修改,下面开始编码。

打开BIDMainViewController.m,添加以下code

从零开始学ios开发(二十):Application Settings and User Defaults(下)
@implementation BIDMainViewController

- (void)refreshFields {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.usernameLabel.text = [defaults objectForKey:kUsernameKey];
self.passwordLabel.text = [defaults objectForKey:kPasswordKey];
self.protocolLabel.text = [defaults objectForKey:kProtocolKey];
self.warpDriveLabel.text = [defaults boolForKey:kWarpDriveKey] ? @"Enabled" : @"Disabled";
self.warpFactorLabel.text = [[defaults objectForKey:kWarpFactorKey] stringValue];
self.favoriteTeaLabel.text = [defaults objectForKey:kFavoriteTeaKey];
self.favoriteCandyLabel.text = [defaults objectForKey:kFavoriteCandyKey];
self.favoriteGameLabel.text = [defaults objectForKey:kFavoriteGameKey];
self.favoriteExcuseLabel.text = [defaults objectForKey:kFavoriteExcuseKey];
self.favoriteSinLabel.text = [defaults objectForKey:kFavoriteSinKey];
} - (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self refreshFields];
}
从零开始学ios开发(二十):Application Settings and User Defaults(下)

首先我们实现了refreshFields方法,里面首先声明了NSUserDefaults,用于获取Settings中的值,之后调用objextForKey,通过Key来获取10个Label的值,有2个比较特殊,第一个是kWarpDriveKey,由于WarpDrive是一个Switch,它返回的是一样bool型,因此通过三元运算符来判断YES或NO,如果是YES,返回“Enabled”,如果是NO,则返回“Disabled”。另一个比较特殊的是WarpFactor,由于WarpFactor是一个slider,返回的是一个int型,所以通过stringValue将int型转换为string输出。

然后我们重载了viewDidAppear方法,在view出现时调用refreshFields方法。

接着在BIDMainViewController.m中找到flipsideViewControllerDidFinish方法,添加如下code

- (void)flipsideViewControllerDidFinish:(BIDFlipsideViewController *)controller
{
[self refreshFields];
[self dismissViewControllerAnimated:YES completion:nil];
}

在Main View的右下角有一个info button,点击它会切换到flipsideView,当从flipsideView切换回来的时候,就会调用上面的这个方法,然后再次刷新Settings中的数据。

好了,编译运行一下程序,程序启动后,在Settings中为AppSettings中的每一项赋值,然后打开AppSettings程序,就可以看到一下类似的截图了。
从零开始学ios开发(二十):Application Settings and User Defaults(下)

3)将值写入Settings
刚才我们通过NSUserDefaults从Settings读取了值,现在我们将学习如何在程序中设置值,然后再写入到Settings中。

打开MainStoryboard.storyboard,在layout area中,将Flipside View Controller布局成如下样子
从零开始学ios开发(二十):Application Settings and User Defaults(下)
将View的背景色改成Light Gray color,View的title改成“Warp Settings”,添加了2个Label,添加了一个Switch和Slider,其中,Slider的左右两个图片是在其Attributs inspector中设置的
从零开始学ios开发(二十):Application Settings and User Defaults(下)
然后将slider的最小值设为1,最大值设为10,当前值设为5,同样也是在Attributes inspector中进行设置
从零开始学ios开发(二十):Application Settings and User Defaults(下)

根据View中的内容,我们可以看出是针对Settings中的switch(WarpDrive)和slider(Warp Factor),打开BIDFlipsideViewController.h,添加如下code

从零开始学ios开发(二十):Application Settings and User Defaults(下)
#import <UIKit/UIKit.h>

@class BIDFlipsideViewController;

@protocol BIDFlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(BIDFlipsideViewController *)controller;
@end @interface BIDFlipsideViewController : UIViewController @property (weak, nonatomic) id <BIDFlipsideViewControllerDelegate> delegate;
@property (weak, nonatomic) IBOutlet UISwitch *engineSwitch;
@property (weak, nonatomic) IBOutlet UISlider *warpFactorSlider; - (void)refreshFields;
- (IBAction)engineSwitchTapped;
- (IBAction)warpSliderTouched;
- (IBAction)done:(id)sender; @end
从零开始学ios开发(二十):Application Settings and User Defaults(下)

两个IBOutlet自然是指向View上的Switch和Slider的,refreshFields是用来刷新Flipside上的数据的,2个IBAction,当swtich发生改变时,触发engineSwitchTapped事件,当slider发生改变时,触发warpSliderTouched事件。

下面就是绑定了,展开Flipside View Controller Scene
从零开始学ios开发(二十):Application Settings and User Defaults(下)
然后选中Flipside View Controller根节点,control-drag到switch上,在弹出的框中选择engineSwitch
同样的方法,control-drag到slider上,选中warpFactorSlider

然后绑定事件,这次在Flipside View Controller选中switch,然后control-drag到Flipside View Controller Scene中的根节点Flipside View Controller上,会弹出一个框
从零开始学ios开发(二十):Application Settings and User Defaults(下)
选中enginSwitchTapped,同学选择slider,control-drag,选择warpSliderTouched

好了,界面上的操作全部完成了,下面开始编码,打开BIDFlipsideViewController.m,添加如下代码

从零开始学ios开发(二十):Application Settings and User Defaults(下)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self refreshFields];
} ...... - (void)refreshFields
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.engineSwitch.on = [defaults boolForKey:kWarpDriveKey];
self.warpFactorSlider.value = [defaults floatForKey:kWarpFactorKey];
} - (IBAction)engineSwitchTapped
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:self.engineSwitch.on forKey:kWarpDriveKey];
} - (IBAction)warpSliderTouched
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setFloat:self.warpFactorSlider.value forKey:kWarpFactorKey];
}
从零开始学ios开发(二十):Application Settings and User Defaults(下)

首先在viewDidLoad中调用refreshFields的方法,接着实现了refreshFields,用于读取Settings中的值并显示在界面上,然后实现了2个IBAction,第一个用于保存Swtich的值,另一个保存Slider的值,2个方法都很简单,看代码就能看懂了。

好,保存编译运行程序,在主界面中点击右下角的info button,切换到flip view
从零开始学ios开发(二十):Application Settings and User Defaults(下)
flip view上显示了Settings中Warp Drive的值和Warp Factor的值,然后我们调整一下,将Warp Engines设为ON,然后改变一下Warp Factor的位置,例如
从零开始学ios开发(二十):Application Settings and User Defaults(下)
然后按左上角的Done,返回main view,可以看到Warp Drive和Warp Factor的值也相应发生了改变
从零开始学ios开发(二十):Application Settings and User Defaults(下)

3)设置默认值
好了,到目前位置,我们已经可以做很多事情了,在App中读取Settings中的值,在App中改变Settings中的值并保存回Settings中,但是大家有没有发现,当你们第一运行app时,main view中其实是空的,什么都没有,只有当我们退出程序,在Settings中设置好值以后,再回到App中,此时main view中的值才会有。其实这个情况是正确的,但是我们更希望能够有一个默认值存在,我们无法在Settings.bundle中设置默认值,但是NSUserDefaults为我们提供了方法,打开BIDAppDelegate.m,添加如下代码

从零开始学ios开发(二十):Application Settings and User Defaults(下)
#import "BIDAppDelegate.h"
#import "BIDMainViewController.h" @implementation BIDAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
NSDictionary *defaults = @{kWarpDriveKey: @YES,
kWarpFactorKey: @5,
kFavoriteSinKey: @"Greed"}; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
return YES;
}
从零开始学ios开发(二十):Application Settings and User Defaults(下)

从代码中可以看到,NSUserDefaults通过registerDefaults方法设置默认值,它的参数是一个NSDictionary,在NSDictionary设置了3个对象的默认值。好了,在重新编译运行程序之前,请确保将模拟器中的AppSettings删除,再编译运行,效果如下
从零开始学ios开发(二十):Application Settings and User Defaults(下)
可以看到,Warp Drive, Warp Factor, Favorite Sin三个对象都有默认值,和我们的预期是一样的。

4)数据的同步
相信大家现在的手机至少是ios4以上的版本了,从ios4开始,ios就支持多任务了(虽然表面上是支持的),用户可以在多个app之间进行切换。我们这个app当然也可以,但是有一个问题,我们运行程序,app默认界面如下
从零开始学ios开发(二十):Application Settings and User Defaults(下)

接着按Home键,回到桌面进入Settings,为Username
从零开始学ios开发(二十):Application Settings and User Defaults(下)
然后退出Settings,再进入AppSettings,你会发现刚才输入的username并没有显示出来
从零开始学ios开发(二十):Application Settings and User Defaults(下)

ok,好,我们现在就来解决这个问题。首先简单的说一下原理,这里用到了ios的一个机制:Notification。当一个后台的程序被激活后,它将收到一个notification:UIApplicationWillEnterForegroundNotification,表示app即将显示到前台来。我们首先定义一个方法,当发生notification时会调用该方法,分别打开BIDMainViewController.m和BIDFlipsideViewController.m,分别添加如下代码

- (void)applicationWillEnterForeground:(NSNotification *)notification
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
[self refreshFields];
}

NSUserDefaults的synchronize方法是用来同步Settings中的值的,当值同步完后,调用refreshFields方法,显示到view中。

再分别为BIDMainViewController.m和BIDFlipsideViewController.m添加如下方法

从零开始学ios开发(二十):Application Settings and User Defaults(下)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated]; UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:app];
}
从零开始学ios开发(二十):Application Settings and User Defaults(下)

该方法用于监听ios发出的notification,当监听到UIApplicationWillEnterForegroundNotification通知后,就调用applicationWillEnterForeground方法。

我们还要更新2个已经写好的方法,engineSwitchTapped和warpSliderTouched(在BIDFlipsideViewController.m中),修改如下

从零开始学ios开发(二十):Application Settings and User Defaults(下)
- (IBAction)engineSwitchTapped
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:self.engineSwitch.on forKey:kWarpDriveKey];
[defaults synchronize];
} - (IBAction)warpSliderTouched
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setFloat:self.warpFactorSlider.value forKey:kWarpFactorKey];
[defaults synchronize];
}
从零开始学ios开发(二十):Application Settings and User Defaults(下)

新增了同步,每当值发生改变,就同步一下。

我们最后还要添加一个方法,用于释放notification,还是分别为BIDMainViewController.m和BIDFlipsideViewController.m添加如下方法

- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

当view消失后(进入后台或者程序退出),将notification释放。

好了,再次编译运行app,按Home键回到桌面,进入Settings修改值再回到AppSettings,会发现相对于的值发生了改变。

5)总结
应该说,这篇以及上一篇关于Settings的内容都已经讲完了,涵盖了绝大部分关于Settings的操作,这部分的内容在程序设计开发的过程中还是相对有用的,对我来说收获很大。下一篇开始,我们将重点讲解ios对于数据的保存功能是如何实现的,又是一个很有用的内容,每个app几乎都会使用到,有些保存的方法其实我们已经学习过了,在下一章会重点再介绍一次,希望下一篇会很快到来,我会努力的!

AppSettings_all.zip

从零开始学ios开发(二十):Application Settings and User Defaults(下)的更多相关文章

  1. 从零开始学ios开发(十八):Storyboards(下)

    这篇我们完成Storyboards的最后一个例子,之前的例子中没有view之间的切换,这篇加上这个功能,使Storyboards的功能完整呈现.在Storyboards中负责view切换的东西叫做“s ...

  2. 从零开始学ios开发(十九):Application Settings and User Defaults(上)

    在iphone和ipad中,有一个东西大家一定很熟悉,那个东西就是Settings. 这次要学习的东西说白了很简单,就是学习如何在Settings中对一个app的某些属性进行设置,反过来,在app中更 ...

  3. 从零开始学ios开发(十二):Table Views(上)

    这次学习的控件非常重要且非常强大,是ios应用中使用率非常高的一个控件,可以说几乎每个app都会使用到它,它就是功能异常强大的Table Views.可以打开你的iphone中的phone.Messa ...

  4. 从零开始学ios开发(十二):Table Views(中)UITableViewCell定制

    我们继续学习Table View的内容,这次主要是针对UITableViewCell,在前一篇的例子中我们已经使用过UITableViewCell,一个默认的UITableViewCell包含imag ...

  5. 从零开始学ios开发(十):Multiview Applications(多个xib之前的切换)

    这篇学习的主要内容是Multiview,在我们学习iphone旋转的时候,介绍过多个view的使用方法,不过这里的view和旋转屏幕中所指的多个view是不同的,旋转屏幕中涉及到的多个view是在一个 ...

  6. 从零开始学ios开发(十四):Navigation Controllers and Table Views(上)

    这一篇我们将学习一个新的控件Navigation Controller,很多时候Navigation Controller是和Table View紧密结合在一起的,因此在学习Navigation Co ...

  7. 从零开始学ios开发(十五):Navigation Controllers and Table Views(中)

    这篇内容我们继续上一篇的例子接着做下去,为其再添加3个table view的例子,有了之前的基础,学习下面的例子会变得很简单,很多东西都是举一反三,稍稍有些不同的内容,好了,闲话少说,开始这次的学习. ...

  8. 从零开始学ios开发(十六):Navigation Controllers and Table Views(下)

    终于进行到下了,这是关于Navigation Controllers和Table Views的最后一个例子,稍微复杂了一点,但也仅仅是复杂而已,难度不大,我们开始吧. 如果没有上一篇的代码,可以从这里 ...

  9. 从零开始学ios开发(十三):Table Views(下)Grouped and Indexed Sections

    在前面2篇关于Table View的介绍中,我们使用的Style都是Plain,没有分组,没有index,这次学习的Table View和iphone中的通讯录很像,有一个个以字符为分割的组,最右边有 ...

  10. 从零开始学 iOS 开发的15条建议

    事情困难是事实,再困难的事还是要每天努力去做是更大的事实. 因为我是一路自学过来的,并且公认没什么天赋的前提下,进步得不算太慢,所以有很多打算从零开始的朋友会问我,该怎么学iOS开发.跟粉丝群的朋友交 ...

随机推荐

  1. 前端自动化构建工具gulp记录

    一.安装 1)安装nodejs 通过nodejs的npm安装gulp,插件也可以通过npm安装.windows系统是个.msi工具,只要一直下一步即可,软件会自动在写入环境变量中,这样就能在cmd命令 ...

  2. DOM 事件深入浅出(一)

    在项目开发时,我们时常需要考虑用户在使用产品时产生的各种各样的交互事件,比如鼠标点击事件.敲击键盘事件等.这样的事件行为都是前端DOM事件的组成部分,不同的DOM事件会有不同的触发条件和触发效果.本文 ...

  3. PHP日常开发工具-Sublime应用

    工欲善其事,必先利其器.这里我推荐Sublime Text3做为PHP编辑器,以下简称为ST3,因为不仅系统资源占用小.打开快速,并且还有如下优点: 插件多,类似Emmet信手拈来,非常顺手. UI很 ...

  4. &lt&semi;转&gt&semi;揭秘DNS后台文件:DNS系列之五

    揭秘DNS后台文件 在前面的博文中我们介绍了DNS的体系结构,常用记录,还介绍了辅助服务器的配置,今天我们来介绍一下DNS服务器背后的几个文件.其实DNS服务器的工作完全依靠这几个文件,了解了DNS的 ...

  5. Codeforces Beta Round &num;18 &lpar;Div&period; 2 Only&rpar; C&period; Stripe 前缀和

    C. Stripe Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/18/C ...

  6. 第五章&lowbar;JSTL

    5.1.下载JSTL http://jstl.java.net 5.2.JSTL类库 类别 下属功能 URI 前缀 Core 变量支持 http://java.sun.com/jsp/jstl/cor ...

  7. Redis简介 Linux安装Redis Redis使用

    其他一些操作(包括 APPEND.GETRANGE.MSET 和 STRLENGTH 也可用于字符串.请参见http://doc.redisfans.com/string/index.html ) 使 ...

  8. ARM-linux与Ubuntu开发工具NFS及流程

    Linux虚拟机的型号是:Ubuntu 12.04 VMware:workstation 14 pro   author: Xianghai Ding Date:2019.01.04  板端:Hi35 ...

  9. 【Redfin SDE intern】跪经

    萌新的面试第一弹 Redfin是我求职生涯中的第一家,第一个电面,第一个onsite.除了结果不好,其他过程都很好... 春节当天风风火火去西雅图面试,之前分配的五个面试官其中有两个中国人,然而全部被 ...

  10. Centos7之Systemd风格

    Unit(单元) /usr/lib/systemd/system       每个服务最主要的启动脚本设置,类似于之前的/etc/init.d目录 关键特性 1.基于socket的激活机制,socke ...