文档章节

iOS开发21:使用Settings Bundle为程序添加设置项

双子座
 双子座
发布于 2012/05/08 12:28
字数 1706
阅读 16316
收藏 30

Settings Bundle是在自己的程序中建立的一组文件,利用它可以告诉设备中的Settings程序我们写的程序有哪些设置项。用户在Settings程序中设置好相关相关选项后回到我们自己的程序,自己的程序中的对应项也会发生相应的变化。

在iOS程序中,用户默认项,即上面所说的设置项,是用NSUserDefaults类实现的。在NSUserDefaults类中使用关键字来读取和存储设置项的具体数据,就像NSDictionary类一样,不同的是,NSUserDefaults类的数据是存储在文件系统中的,而不是作为一个对象实例放在内存中。

在这篇文章中,我们将创建一个程序,为它添加和配置Settings Bundle,之后可以在Settings程序中显示和配置相关选项。在Settings Bundle中使用plist文件来定义程序中允许的设置项,Settings程序会自动建立接口。Settings Bundle中的plist文件必须遵循特定的格式,不过Xcode会帮助我们遵循这种格式。

1、首先下载初始代码。http://www.oschina.net/code/snippet_164134_10458

由于我们的重点是Settings Bundle的使用,那么建立工程、实现页面跳转等等就不详细说明了。

2、解压Settings Bundle Test.zip,使用Xcode 4.3打开此工程,先打开FirstViewController.xib,使用IB向其中添加控件,如下图:

然后为这些标签向FirstViewController.h中建立Outlet映射:

3、打开MoreViewController.xib,向其中添加控件,如下:

然后,向MoreViewController.h中,为右边的两个Label以及UISlider与UISWitch控件创建Outlet映射,为UISlider与UISWitch控件添加Action映射:

然后在Attribute Insepector中设置UISlider控件最小值、最大值和默认值分别是0、10和5:

将准备好的两张图片添加到工程中,在Attribute Insepector中设置UISlider控件的Min Image与Max Image:

4、接下来,为程序建立Settings Bundle。依次选择File — New — File…,找到Settings Bundle:

单击Next,设置好名称和分组:

然后单击Create,则创建了Settings.bundle。

5、展开Settings.bundle,其中包含一个Root.plist。Settings程序中的显示项就是从Root.plist中获取的。

单击Root.plist以打开它,在空白处单击,选中Show Raw Keys/Values:

接下来,我们展开PreferenceSpecifiers那一项,删除除了Group之外的其他项。

PreferenceSpecifiers这个对应于刚打开Settings程序时第一页中该应用程序的一个标签,如果此时运行程序,然后在模拟器返回桌面,再打开Settings程序,则其中会出现Settings Bundle Test这一项:

上图中的Settings Bundle Test这一项就可以理解为是从PreferenceSpecifiers获取的。

6、展开PreferenceSpecifiers这一项,先向其中添加三行,每一行的设置如下:

此时运行程序,在Settings程序中单击上图中的Settings Bundle Test那一项,出现的页面如下图:

   

在Root.plist文件中,Item 0那一项的类型是PSGroupSpecifier,它表示一个分组,则它下面的每Item 1到Item 3都是在这一组,直到下一个PSGroupSpecifier出现。

Item 1与Item 2都是PSTextFieldSpecifier类型的,它们都是文本框,可以通过为其添加子项限制这些文本框的输入。

Item 3是一个多选框,可供选择的值是由Titles与Values决定的,Titles与Values这两项内容是一样的,但是缺一不可。

7、之后,再向其中添加Item 4到Item 7,如下图:

再运行程序,打开Settings程序看看:

   

8、之后,我们实现在上面左图的下方出现一项“更多设置”,单击此项跳转到新的页面。先创建一个plist文件,名称为MoreSettings.plist,创建方法就不说了吧,参考http://my.oschina.net/plumsoft/blog/42084第二步。注意现在只是创建到工程中而不是Settings.bundle中,想要加到Settings.bundle中还要其他操作,稍后详解。

右击Settings.bundle,选择Show in Finder:

然后在Finder中右击Settings.bundle,选择“显示包含内容”:

在打开的地方将MoreSettings.plist以及上面用到的两张图片拷贝进去。

9、编辑Settings.bundle中的MoreSettings.plist内容如下:

保存后,在Root.plist添加一行:

注意,Item 8的类型是通过选择其子选项Type的类型改变的。

此时运行程序,Settings程序如下:

   

10、接下来都是代码了。

10.1 在ViewController.h中添加代码:

#define kUserName @"username"
#define kPassWord @"password"
#define kGender @"gender"
#define kFavouriteColor @"favouritecolor"
#define kFavouriteSeason @"favouriteseason"
#define kFavouriteSport @"favouritesport"
#define kTheSlider @"theslider"
#define kTheSwitch @"theswitch"

10.2 在FirstViewController.h与MoreViewController.h中分别声明一个方法,名为

- (void)refreshFields;

在FirstViewController.m中添加代码如下:

- (void)refreshFields {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.userNameLabel.text = [defaults objectForKey:kUserName];
    self.passWordLabel.text = [defaults objectForKey:kPassWord];
    self.genderLabel.text = [defaults objectForKey:kGender];
    self.colorLabel.text = [defaults objectForKey:kFavouriteColor];
    self.seasonLabel.text = [defaults objectForKey:kFavouriteSeason];
    self.sportLabel.text = [defaults objectForKey:kFavouriteSport];
}

在MoreViewController.m中添加代码如下:

- (void)refreshFields {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.theSwitch.on = [defaults boolForKey:kTheSwitch];
    self.slider.value = [defaults floatForKey:kTheSlider];
    self.sliderValueLabel.text = [[defaults objectForKey:kTheSlider]stringValue];
}

10.3 实现MoreViewController.m中的sliderTapped与switchTapped方法如下:

- (IBAction)sliderTapped:(id)sender {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setFloat:self.slider.value forKey:kTheSlider];
    self.sliderValueLabel.text = [[defaults objectForKey:kTheSlider] stringValue];
    [defaults synchronize];
}
- (IBAction)switchTapped:(id)sender {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setBool:self.theSwitch.on forKey:kTheSwitch];
    [defaults synchronize];
}

10.4 在FirstViewController.m与MoreViewController.m中@end之前都添加代码:

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

10.5 在FirstViewController.m与MoreViewController.m的viewDidLoad方法中都添加代码:

[self refreshFields];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:app];

10.6 在FirstViewController.m与MoreViewController.m中的ViewDidUnload方法中都添加代码:

[[NSNotificationCenter defaultCenter] removeObserver:self];

11.7 在ViewController.m的viewDidLoad方法中的[super viewDidLoad];之前添加代码:

//注册默认项
NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], kTheSwitch,
                          [NSNumber numberWithFloat:5.0], kTheSlider,
                          nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];

11、运行,那么Settings Bundle Test程序中的数据将会随着Settings程序中的选项改变而改变,反过来也是。

例如,在Settings程序中设置如下:

   

返回Settings Bundle Test程序,显示如下:

   

不过,第一次运行程序时,单击“更多设置”按钮,Slider与Switch是变形的,然后才会显示正确的值:

真是好事多磨啊。

刚运行程序,第一次单击“更多设置”按钮就会出现上图情况。猜想是因为刚开始ViewController中的moreViewController为空,在页面跳转时才创建它。为此,试试在ViewController.m的viewDidLoad方法的最后一条语句之前添加代码:

self.moreViewController = [[MoreViewController alloc] initWithNibName:@"MoreViewController" bundle:nil]; 
self.moreViewController.viewController = self;

再运行试试,还是不行。那估计是跟页面跳转时的动态效果有关了。再把ViewController.m的switchViews方法修改如下:

- (void)switchViews {
    if (self.moreViewController.view.superview == nil) { 
        if (self.moreViewController == nil) { 
            self.moreViewController = [[MoreViewController alloc] initWithNibName:@"MoreViewController" bundle:nil]; 
            self.moreViewController.viewController = self;
        }
    } else { 
        if (self.firstViewController == nil) { 
            self.firstViewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];
            self.firstViewController.viewController = self;
        } 
    }
    [UIView beginAnimations:@"View Flip" context:nil]; 
    [UIView setAnimationDuration:0.80]; 
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    if (self.moreViewController.view.superview == nil) { 
        [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES]; 
        [self.firstViewController.view removeFromSuperview];
        [self.view insertSubview:self.moreViewController.view atIndex:0]; 
    } else { 
        [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES]; 
        [self.moreViewController.view removeFromSuperview]; 
        [self.view insertSubview:self.firstViewController.view atIndex:0]; 
    } 
    [UIView commitAnimations]; 
}

再运行,问题总算解决了。

最终代码:http://www.oschina.net/code/snippet_164134_10484

 

© 著作权归作者所有

共有 人打赏支持
双子座
粉丝 539
博文 78
码字总数 61009
作品 0
南京
程序员
加载中

评论(17)

泥彩
泥彩
成功,谢谢
G
GlorySimba
谢谢博主的分享!
z
zk0301
iphone的settings还有那么古怪的功能,真心不习惯。管的太多了吧。汗~ 下一篇 冲啊
路上的问候
路上的问候
嘻嘻,把问题写出来了,确突然解决了。。
是在RootViewController.m中有对rootViewController_d 的附值:
self.secondViewController.rootViewController_second = self;
self.firstViewController.rootViewController_first = self;
路上的问候
路上的问候
您好,我解决了以上问题,但是还有个问题:
问下:我下载了你的代码,你代码中是@class RootViewController;
用按钮实现了两个视图的切换,
在FirstViewController.h中@class RootViewController;以及@property (strong, nonatomic) RootViewController *rootViewController_d;
在FirstViewController.m中#import "RootViewController.h"以及@synthesize rootViewController_d;
然后通过按钮的方法调用了RootViewController.h/.m中的switchViewsAction方法:
- (IBAction)switchBTNaction:(id)sender{
  [self.rootViewController_d switchViewsAction];
  //NSLog(@"aaaaaa");
  }
我调试怎么也进不了RootViewController.m中的switchViewsAction方法?????????
但是不提示错误呀。

我想不明白:FirstViewController.m只是声明一个RootViewController *rootViewController_d;
是在哪里真正附值呢?
我调试的也是:
rootViewController_d  RootViewController *  0x00000000
路上的问候
路上的问候
为什么我的slider就是不能在设置里显示吖?
新风作浪
新风作浪
请问下,为什么我的Root.plist文件里面Item0里Type不能改成PSGroupSpecifier,而且改完后编程Group
双子座
双子座

引用来自“cos于鹏飞”的评论

总结一下我的问题,有几个问题补充一下还望解答
<第4节>为什么创建Settings.bundle的时候不能重命名?,这里系统有默认吗?
<第11.7节>为什么要把这个代码加载[super viewDidLoad];之前?我实验了一下,加载后面也是可以的,这里有什么规范或者什么注意点吗?
<关于文章末尾的BUG>我仔细看了下这部分代码的区别,你怎么看待这个BUG?如下结论能否得出?:界面切换之前必须创建界面,否则会出现异常。
但是很奇怪的是,在viewDidLoad()中添加了self.moreViewController的初始化之后,断点你的程序启动第一次翻页操作,无论修改前还是修改后,你switchViews()下的if (self.moreViewController == nil)这一句都是走不进去的,因为self.moreViewController 必然不为空,那么还会有区别呢?

1、手机启动后,设置程序会找到每个程序的Settings.bundle,从而在设置程序中显示。所以,必须是Settings.bundle,不能用其他的名称
2、我是习惯加在[super viewDidLoad];之前,大部分情况下随便,不过也有例外的时候
3、最后一段代码,我印象中当时修改的是关于动态效果的代码,而对代码原来的结构没有改变。产生区别的是动态效果的代码。if (self.moreViewController == nil)是比较保险的写法,我看一本英文书中写的,当系统资源不足的时候,当前未使用的变量会被销毁。都过了很久了,有点忘了原文是怎么讲的了
cos于鹏飞
cos于鹏飞
总结一下我的问题,有几个问题补充一下还望解答
<第4节>为什么创建Settings.bundle的时候不能重命名?,这里系统有默认吗?
<第11.7节>为什么要把这个代码加载[super viewDidLoad];之前?我实验了一下,加载后面也是可以的,这里有什么规范或者什么注意点吗?
<关于文章末尾的BUG>我仔细看了下这部分代码的区别,你怎么看待这个BUG?如下结论能否得出?:界面切换之前必须创建界面,否则会出现异常。
但是很奇怪的是,在viewDidLoad()中添加了self.moreViewController的初始化之后,断点你的程序启动第一次翻页操作,无论修改前还是修改后,你switchViews()下的if (self.moreViewController == nil)这一句都是走不进去的,因为self.moreViewController 必然不为空,那么还会有区别呢?
cos于鹏飞
cos于鹏飞
为啥创建Settings.bundle的时候不能重命名?我重命名的就都显示不出来,没有重命名而是使用系统默认命名的就成功了?
iOS开发23:通过归档永久存储数据

之前一篇文章《iOS开发20:使用Settings Bundle为程序添加设置项》中简单介绍了怎样在Settings程序中设置自己的程序,并实现保存,使得下次运行自己的程序时显示的还是上次的设置项。而上一篇...

双子座
2012/05/12
0
11
iOS Settings.bundle 创建和使用(系统设置中展示App版本等信息)

//联系人:石虎 QQ:1224614774 昵称:嗡嘛呢叭咪哄 一、概念 在iOS开发中很多时候开发者需要让用户自行设置一些系统的配置项目,在系统设置中展示App版本等信息 在设备设置中,App权限下面展示自...

石虎132
05/28
0
0
【AR】开始使用Vuforia开发iOS(2)

原 设置iOS开发环境 安装Vuforia iOS SDK 如何安装Vuforia iOS示例 编译并运行Vuforia iOS示例 支持iOS金属 iOS 64位迁移 设置iOS开发环境 适用于iOS的Vuforia引擎目前支持运行iOS 9及更高版...

lichong951
06/11
0
0
iOS Provisioning Portal概述

注意: iOS Provisioning Portal 仅可以在PC上的 Safari和Firefox浏览器中有效。 iOS Provisioning Portal概述 概述 和 provisioning(服务提供) 助手执行的自动设置不同, iOS Provisioning...

JohnZr
2012/09/26
0
0
一步一步学习iOS 5编程(第三版)-PDF中文版-正式发布!

目前,这是第一本介绍iOS 5.x 和 Xcode 4.4 的中文版书籍,尤其适合于iOS 编程开发初学者。本教程由 EntLib.com 团队编写。如有任何技术问题,欢迎留言。 电子版 – PDF 格式,支持iPhone、i...

entlib
2012/09/20
0
2

没有更多内容

加载失败,请刷新页面

加载更多

TypeScript基础入门之JSX(二)

转发 TypeScript基础入门之JSX(二) 属性类型检查 键入检查属性的第一步是确定元素属性类型。 内在元素和基于价值的元素之间略有不同。 对于内部元素,它是JSX.IntrinsicElements上的属性类型...

durban
21分钟前
0
0
AVA中CAS-ABA的问题解决方案AtomicStampedReference

了解CAS(Compare-And-Swap) CAS即对比交换,它在保证数据原子性的前提下尽可能的减少了锁的使用,很多编程语言或者系统实现上都大量的使用了CAS。 JAVA中CAS的实现 JAVA中的cas主要使用的是...

码代码的小司机
24分钟前
0
0
Android JNI开发系列(十三) JNI异常处理

JNI 异常处理 JNI异常与JAVA处理异常的区别 JAVA 有异常处理机制,而JNI没有 如果JAVA中异常没有捕获,后面的代码不会执行,JNI会执行 JAVA编译时的异常,是在方法显示的声明了某一个异常,编...

蔡小鹏
37分钟前
2
0
简单介绍Java 的JAR包、EAR包、WAR包区别

WAR包 WAR(Web Archive file)网络应用程序文件,是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件。War专用于Web方面。大部分的JAVA WEB工程,都是打成WAR包进行发布的。 War是...

Linux就该这么学
今天
1
0
Qt那些事0.0.7

在帮助文档(Overview - QML and C++ Integration)中随缘遇到一张图,是关于C++对象与QML整合介绍的,值得标记下来,虽然大部分功能也有所涉猎,但是还是留个记号,万一哪天我失忆了还想写Q...

Ev4n
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部