在 Swift 中使用 SETTINGS BUNDLES

在 Swift 中使用 SETTINGS BUNDLES,第1张

概述原文:USING SETTINGS BUNDLES WITH SWIFT 作者:STEVEN LIPTON 译者:kmyhy 你是否知道怎样将用户定义的设置放系统设置程序中?Xcode 通过创建一个特殊的 plist 文件 settings.bunlde 将多个值以 NSUserDafulats 的方式添加到设置程序中。在本教程中你将学习如何在 app 中创建 settings.bundle ,从

原文:USING SETTINGS BUNDLES WITH SWIFT
作者:STEVEN LIPTON
译者:kmyhy

你是否知道怎样将用户定义的设置放系统设置程序中?Xcode 通过创建一个特殊的 pList 文件 settings.bunlde 将多个值以 NSUserDafulats 的方式添加到设置程序中。在本教程中你将学习如何在 app 中创建 settings.bundle ,从而在设置程序中访问 xml。在后续的教程中,我们会通过 pList 编辑器深入讨论 settings.bundle。

本教程假设你已经知道如何使用 pList 和 NSUserDefaults。如果你不知道,你可以在这里找到我之前发的关于 Property Lists 和 NSUserDefaults 的帖子。

创建 Settings.bundle

新建 Single vIEw application 项目,名为 SettingsBundleDemo ,勾选 Swift 和 Universal device。

在 SettingsBundleDemo 文件夹上右键,选择 New file。然后选择 Resources 类下的 Settings Bundle 再点击 Next。

文件会以 settings 命名。在保存窗口中,确保 settings.bundle 位于 SettingsBundleDemo 文件夹(注:这点很重要)。点击 Create。

系统将打开 settings.bundle。它看起来像一个编译过的包。在导航窗口中,点击箭头展开 settings.bundle。

点击 Root.pList 文件。你会看到一个 pList 文件:

如果 Preference Items 项是收起的,请展开它。这个里面有一些实例数据。和别的 PList 不同,这里的数据不会直接将值存储为字典,而是一个字典的数组,每个字典都表示一个控件。你可以在这个 pList 文件中描述你想要的控件,然后在设置程序中会显示这个控件。当我们将 settings.bundle 和 NSUserDefaults.standardUserDefaults 关联起来时,系统会在 NSUserDefaults 中创建 key 和 value。

下面列出你将用到的控件:

每个控件都有许多属性。如果 Group Control 当前未展开,请展开它,在 Root.pList 中,它是 Item 0。

Group 控件通常用于将其他控件组合在一起。它只有 Title 和 Type 属性。展开 Item 3(SlIDer)。

slIDer 有更多的属性,都列在了这里。很多控件都会有一个 Default Value 属性,这个值会在设置 app 中显示,它并不会在 defaults 中保存。这个值会在第一次使用时显示这个值,但只是用于显示,而不是一个真正的值。

译者注:也就是说,虽然你给控件指定了 Default Value,但第一次运行 APP 时,这个控件所存储的值仍然是 nil。Default Value 仅用于显示,不会被存储。

每种控件都有不同的属性,如上表所示。这里列出了 Root.pList 中的所有属性:

加入自己的设置

删除所有控件。在 Root.pList 中删除 pList 比较麻烦。最简单的办法是将 item 剪切掉。选中 Item 0 (Group),在 group 上右键,选中快捷菜单中的 Cut。对 Item 3(SlIDer) 和其他控件进行同样的 *** 作。现在你的 PList 将是这个样子:

选中 Preferencce Items,确保它被展开。此时箭头应当是向下。按它旁边的 Add(+) 按钮。会创建一个新的项:

这时会显示一个d出式菜单。如果你不小心点击了别的地方,这个菜单又会消失,这时你可以点击它右边的下箭头(),菜单又会出现,列出一个控件列表:

选择其中的 Toggle Switch。我们用它来存储 Bool 值。展开 Toogle Switch 会呈现如下属性:

为每个属性赋值,将 Title 设置为 Room for cream,IDentifIEr 设置为 coffee_cream。这个 IDentifIEr 属性就是值存在 NSUserDefaults 后的 key 。将 Default Value 设置为 YES。最终是这个样子:

关闭 switch 控件的属性,悬着 Item 0。点击右键,然后选择 Add Row。在类型菜单中选择 Text FIEld,其实这也是默认的类型。展开 Item 1(Text FIEld),查看它的属性:

将 Title 设置为 Beverage of choice,IDentifer 设为 coffee_type。右键点击 IDentifIEr 然后选择 Add Row。这会创建一个新行,并让你选择合适的属性:

选择 Default Value。并设为 Coffee。

关闭 Text 的属性。选中 Preference items,右键点击并选择 Add Row。新的行会插入到其他行之上,变成 Item 0。类型选择 Multi-Value。Multi-Value 有两个数组属性,用于显示一个选项列表。展开 multi-value ,将 Title 设置为 Size,Default Value 设置为 0,IDentifIEr 设置为 coffe_size。

这个控件不会自动提供值数组。我们必须手动提供。选中最下面的属性,右键点击,选择 Add Row。行类型选择 Values。展开 Values 数组,现在它是空的。通过 Add row 或者 + 按钮,在 Values 中添加 4 个子项。第一行的值设置为 0,类型修改为 Number。类似地将其他行设置为 1,2,3。

关闭 Values。为 multi-value 控件添加另一个属性 Titles。在 Titles 数组下添加 4 个子项,将值分别设置为字符串的 Small、Medium、Large 和 Extra Large。

现在来看看我们的设置界面。为了醒目起见,我们将 Launchscreen.storyboard 背景色设置为成色(#ff8000)。编译运行,当背景色显示出红色时,切换到设置程序。如果使用真机测试,请点击 Home 键,模拟器请按 command+shift+H 键。打开设置 app。

向下滚动,你会看到你的 app 图标。点击你的 app 图标,进入 app 的设置页面。

编辑故事板

停止 app,打开 Main.storyboard,在故事板中拖入一个 switch,一个 label,一个 text fIEld 和一个 segmented control。将这些控件设置成这个样子:

选择 switch,在 size 面板中,设置 Compression Resistance (别挤我)和 Content Hugging (别拉我)的水平和垂直都设置为 1000。这样 switch 的尺寸永远不会改变,设置这两项主要是起这个作用(系数越高,则越晚被压缩和拉伸)。

点击 stack vIEw 按钮,创建一个水平布局的 stack vIEw。然后选择中故事板所有 UIVIEw。再次点击 stack vIEw 按钮创建一个垂直布局的 stack vIEw,设置它的属性为:

Pin 这个 stack vIEw 为:上 71,左 5,右 5。 Update frames 选择为 items of new constraints。

打开助手编辑器,为这些控件创建合适的 UIoUtlet 连接:

@H_502_81@@IBOutlet weak var roomForCream: UISwitch!@IBOutlet weak var drinkText: UITextFIEld!@IBOutlet weak var sizeSegment: UISegmentedControl! 读取 settings.bundle

NSUserDefaults 并不知道我们创建了一个 settings.bundle。我们第一件事情就是向 NSUserDefaults 注册我们的 settings.bundle。

@H_502_81@func registerSettingsBundle(){ let appDefaults = [String:AnyObject]() NSUserDefaults.standardUserDefaults().registerDefaults(appDefaults)}

这个方法向 NSUserDefaults.standardUserDefaults 注册 settings.bundle。regusterDefaults 方法在资源目录中搜索 pList 文件并将字典中存放的键值类型修改为 [String:AnyObject]。这个方法只需要在我们的代码中执行一次。

新增一个方法 updatedisplayFromDefaults 用于读取我们的 defaults:

@H_502_81@func updatedisplayFromDefaults(){ //获得 defaults 引用 let defaults = NSUserDefaults.standardUserDefaults()}

然后,读取键值对并赋给我们的 IBOutlet 组件。继续在声明的方法中添加如下代码:

@H_502_81@//将控件的默认值设置为 default 中存储的值 roomForCream.on = defaults.boolForKey("coffee_cream") if let drink = defaults.stringForKey("coffee_type"){ drinkText.text = drink } else{ drinkText.text = "" } sizeSegment.selectedSegmentIndex = defaults.integerForKey("coffee_size")

stringForKey 方法返回的是一个可空类型。我们的代码需要判断值是否为空并针对性地处理。在 vIEw DIDLoad 方法中调用新方法:

@H_502_81@overrIDe func @H_502_144@vIEwDIDLoad() { super.vIEwDIDLoad() @H_502_144@registerSettingsBundle() @H_502_144@updatedisplayFromDefaults() }

我们想在 app 启动时就开始刷新。回到模拟器或真机上。删除 App。这时 app 和 app 的设置数据都会被删除。我们的 app 偏好设置又被清空了,因为它们并没有被写到 app 中。而且 pList 中的 Default Value 只是一个显示值,它没有真实反应出用户选择。

按下 command+shift+H,切到设置程序。设置你的偏好设置:

按下 command+shift+HH,回到示例 app。我们的 app 仍然没有任何变化。

关闭 app ,回到 Xcode。重新运行 app。现在读到我们的 defaults 了。

用观察者模式同步 defaults

通过重启来刷新偏好设置不是很友好。问题是,我们需要告诉 app 有东西被改变了。并且需要自动进行刷新。在 app 中,无论是 settings.bundle 还是 NSUserDefaults,都面临着这个问题。你修改了一个设置,然后想到处刷新这个新值。这种改变需要通知观察者。

NSUserDefaults 类会产生一种通知,叫做 NSUserDefaultsDIDChangeNotification。我们可以让观察者监听这种通知,当改变发生时调用某些代码。修改 vIEwDIDLoad 方法:

@H_502_81@overrIDe func vIEwDIDLoad() { super.vIEwDIDLoad() registerSettingsBundle() updatedisplayFromDefaults() NSNotificationCenter.defaultCenter().addobserver(self,selector: "defaultsChanged",name: NSUserDefaultsDIDChangeNotification,object: nil) }}

我们让通知中心记住我们已经注册了一个观察者。我们为 NSUserDefaultsDIDChangeNotification 注册了一个观察者,告诉通知中心,当收到这个通知时,执行观察者的 defaultsChanged 方法。

另外,你可能想将 registerSettingsBundle 的代码合并到 updatedisplayFromDefaults 中。这样,每执行一次 registerSettingsBundle,都会改变 NSUserDefaults,增加一份 defaults。而每增加一个值我们会收到一个通知,又会触发一次递归调用,导致内存耗尽。因此,请保持 registerSettingsBundle 作为一个独立的方法。
当收到通知时,我们需要运行 defaultsChanged 方法。这个方法实现如下:

@H_502_81@func @H_502_144@defaultsChanged(){ @H_502_144@updatedisplayFromDefaults() }

还需要写一些常规的代码。在 iOS9 之前,为了保持良好的内存管理,我们需要注销观察者。从 iOS9 开始,ARC 会自动为你注销。对于 iOS 8 设备,则需要用以下代码来注销观察者:

@H_502_81@deinit { //在 iOS9 以后不再需要,ARC 自动会移除观察者。NSNotificationCenter.defaultCenter().removeObserver(self)}

这些代码放在 Swift 类的 deinit 方法里,将观察者从通知中心移除。

模拟器中的一个 BUG

编译运行。按下 Command+shift+H,切换到设置程序。选择设置->SettingsBundleDemo … 出现一片空白。

在真机上不会这样。只有在模拟器中,这才会发生。似乎模拟器仍然在 app 的上一次运行中。当你点击 Xcode 中的 Stop 按钮,它不会终止设置程序。点击 command+shift+HH 或者双击 Home 按钮。向上滑动设置程序,将它终止进程。重新启动设置程序,设置程序才会刷新。你又可以看到 app 的设置页面了。将设置修改为:

回到 SettingsBundleDemo,这次是这个样子:

关于 settings.bundle 的基本介绍就到这里。另外还有一些高级技巧,比如子设置页,以及直接以代码 *** 作设置中的 XML。下面列出了 Root.pList 的代码供你参考

完整代码 @H_502_81@//// VIEwController.swift// SetttingsBundleDemo//// Created by Steven lipton on 3/11/16.// copyright © 2016 MakeAppPIE.Com. All rights reserved.//import UIKitclass VIEwController: UIVIEwController { @IBOutlet weak var roomForCream: UISwitch! @IBOutlet weak var drinkText: UITextFIEld! @IBOutlet weak var sizeSegment: UISegmentedControl! deinit { //Not needed for iOS9 and above. ARC deals with the observer. NSNotificationCenter.defaultCenter().removeObserver(self) } func registerSettingsBundle(){ let appDefaults = [String:AnyObject]() NSUserDefaults.standardUserDefaults().registerDefaults(appDefaults) //NSUserDefaults.standardUserDefaults().synchronize() } func updatedisplayFromDefaults(){ //Get the defaults let defaults = NSUserDefaults.standardUserDefaults() //Set the controls to the default values. roomForCream.on = defaults.boolForKey("coffee_cream") if let drink = defaults.stringForKey("coffee_type"){ drinkText.text = drink } else{ drinkText.text = "" } sizeSegment.selectedSegmentIndex = defaults.integerForKey("coffee_size") } func defaultsChanged(){ updatedisplayFromDefaults() } @IBAction func updateDefaults(sender: AnyObject) { updatedisplayFromDefaults() } overrIDe func vIEwDIDLoad() { super.vIEwDIDLoad() registerSettingsBundle() updatedisplayFromDefaults() NSNotificationCenter.defaultCenter().addobserver(self,object: nil) } overrIDe func dIDReceiveMemoryWarning() { super.dIDReceiveMemoryWarning() // dispose of any resources that can be recreated. }} Root.pList

你可以以 XML 方式来编辑你的 pList 文件,因为种种原因,我们不展开讨论。这里仅列出本示例中使用的 pList 的 XML 源代码:

@H_502_81@<?xml version="1.0" enCoding="UTF-8"?><!DOCTYPE pList PUBliC "-//Apple//DTD PList 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><pList version="1.0"><dict> <key>Stringstable</key> <string>Root</string> <key>PreferenceSpecifIErs</key> <array> <dict> <key>Type</key> <string>PSMultiValueSpecifIEr</string> <key>Title</key> <string>Size</string> <key>Key</key> <string>coffee_size</string> <key>DefaultValue</key> <string>0</string> <key>Values</key> <array> <integer>0</integer> <integer>1</integer> <integer>2</integer> <integer>3</integer> </array> <key>Titles</key> <array> <string>Small</string> <string>Medium</string> <string>Large</string> <string>Extra Large</string> </array> </dict> <dict> <key>Type</key> <string>PSToggleSwitchSpecifIEr</string> <key>Title</key> <string>Room for cream</string> <key>Key</key> <string>coffee_cream</string> <key>DefaultValue</key> <true/> </dict> <dict> <key>Type</key> <string>PSTextFIEldSpecifIEr</string> <key>Title</key> <string>Beverage of Choice</string> <key>Key</key> <string>coffee_type</string> <key>DefaultValue</key> <string>Coffee</string> </dict> </array></dict></pList> 总结

以上是内存溢出为你收集整理的在 Swift 中使用 SETTINGS BUNDLES全部内容,希望文章能够帮你解决在 Swift 中使用 SETTINGS BUNDLES所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1070643.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存