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

在上一篇的学习中,我们知道了如何为一个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,添加如下代码

复制代码
#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
复制代码

上面的代码定义了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,将其背景色变为白色

在Main View的右下角,有一个Info button(一个圆圈,中间有一个字母i),选中它,然后在Attribute inspector中将其Type改成“Info Dark”

这样就能够很容易的找到它所在的地方了

如果你觉得直接在Main View中选择一个白色的Info button很困难,那么你可以打开Main View Controller Scene,在里面你可以方便的找到它

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

根据下图的样子,将Label拖入到Main View中

排列什么的无所谓,自己喜欢就好,主要是右边的10个Label,他们的宽度都是到最右边出现辅助线的位置,以保证能够最大限度容纳字符。

好了,下面的工作就是关联IBOutlet和view上面的Label了,一共要关联10个Label,选中Main View Controller Scene中的Main View Control,control-drag到Label上(右边的一排Label),在弹出的框中选中相对应的IBOutlet

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

打开BIDMainViewController.m,添加以下code

复制代码
@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]; }
复制代码

首先我们实现了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程序,就可以看到一下类似的截图了。

 

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

打开MainStoryboard.storyboard,在layout area中,将Flipside View Controller布局成如下样子

将View的背景色改成Light Gray color,View的title改成“Warp Settings”,添加了2个Label,添加了一个Switch和Slider,其中,Slider的左右两个图片是在其Attributs inspector中设置的

然后将slider的最小值设为1,最大值设为10,当前值设为5,同样也是在Attributes inspector中进行设置

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

复制代码
#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
复制代码

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

下面就是绑定了,展开Flipside View Controller Scene

然后选中Flipside View Controller根节点,control-drag到switch上,在弹出的框中选择engineSwitch
同样的方法,control-drag到slider上,选中warpFactorSlider

然后绑定事件,这次在Flipside View Controller选中switch,然后control-drag到Flipside View Controller Scene中的根节点Flipside View Controller上,会弹出一个框

选中enginSwitchTapped,同学选择slider,control-drag,选择warpSliderTouched

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

复制代码
- (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]; }
复制代码

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

好,保存编译运行程序,在主界面中点击右下角的info button,切换到flip view

flip view上显示了Settings中Warp Drive的值和Warp Factor的值,然后我们调整一下,将Warp Engines设为ON,然后改变一下Warp Factor的位置,例如

然后按左上角的Done,返回main view,可以看到Warp Drive和Warp Factor的值也相应发生了改变

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

复制代码
#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; }
复制代码

从代码中可以看到,NSUserDefaults通过registerDefaults方法设置默认值,它的参数是一个NSDictionary,在NSDictionary设置了3个对象的默认值。好了,在重新编译运行程序之前,请确保将模拟器中的AppSettings删除,再编译运行,效果如下

可以看到,Warp Drive, Warp Factor, Favorite Sin三个对象都有默认值,和我们的预期是一样的。

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

接着按Home键,回到桌面进入Settings,为Username

然后退出Settings,再进入AppSettings,你会发现刚才输入的username并没有显示出来

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添加如下方法

复制代码
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillEnterForeground:)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:app]; }
复制代码

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

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

复制代码
- (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];
}
复制代码

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

我们最后还要添加一个方法,用于释放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

转载于:https://www.cnblogs.com/lovewx/p/3824249.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值