首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》26.1 NSUserDefaults

关灯直达底部

NSUserDefaults提供了一个类方法standardUserDefaults,用于获取NSUserDefaults单例。NSUserDefaults单例以键-值对的形式存储了一系列用户偏好设置。其中,键是用户偏好设置的名称,值是对应的某类数据。与NSDictionary类似,可以通过objectForKey:和setObject:forKey:存取数据。

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSString *greeting = [defaults objectForKey:@“FavoriteGreeting”];

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

[defaults setObject:@“Hello” forKey:@“FavoriteGreeting”];

对于setObject:forKey:,NSUserDefaults会自动将对象存储到对应的plist文件中——显然,对象的类型必须是plist文件可以存储的类型,包括:NSArray、NSDictionary、NSString、NSData、NSDate和NSNumber。如果需要存储plist文件不支持的类型,可以先将其归档为NSData类型,再存入plist文件。

如果通过objectForKey:获取一项没有值的用户偏好设置,NSUserDefaults会返回该项的出厂设置,也称为默认设置。这类设置并没有存储在plist文件中,需要在每次应用启动时向NSUserDefaults注册。为了确保在代码中访问NSUserDefaults之前注册好出厂设置,可以在应用程序委托中覆盖类方法initialize,代码如下:

+ (void)initialize

{

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSDictionary *factorySettings = @{@“FavoriteGreeting”: @“Hey!”,

@“HoursBetweenMothershipConnection : @2};

[defaults registerDefaults:factorySettings];

}

Objective-C运行环境(Objective-C runtime)会在创建某个类的第一个对象之前调用该类的initialize方法。

本节将为Homepwner添加一项用户偏好设置,可以在添加BNRItem对象时默认显示用户设置的名称和价值。

注册出厂设置

应用启动时,首先需要向NSUserDefaults注册出厂设置。通过NSUserDefaults对象存取数据时,使用的键必须是NSString对象。通常情况下,可以将这类字符串定义成静态变量。这样就不用每次使用写死的字符串,直接使用相应的变量即可。使用静态变量有两个好处,一是方便修改,二是可以避免输入错误(如果输错了变量名,编译器就会发出警告;但是,如果输错了字符串,则不会有任何提示)。

打开BNRAppDelegate.h,声明两个NSString类型的静态变量,代码如下:

#import <UIKit/UIKit.h>

extern NSString * const BNRNextItemValuePrefsKey;

extern NSString * const BNRNextItemNamePrefsKey;

@interface BNRAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

再打开BNRAppDelegate.m,实现两个静态变量,然后将其作为键在initialize方法中注册出厂设置:

#import ”BNRAppDelegate.h“

#import ”BNRItemsViewController.h“

#import ”BNRItemStore.h“

NSString * const BNRNextItemValuePrefsKey = @”NextItemValue“;

NSString * const BNRNextItemNamePrefsKey = @”NextItemName“;

@implementation BNRAppDelegate

+ (void)initialize

{

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSDictionary *factorySettings = @{BNRNextItemValuePrefsKey: @75,

BNRNextItemNamePrefsKey: @”Coffee Cup“};

[defaults registerDefaults:factorySettings];

}

读取用户偏好设置

下面在BNRItemStore.m的createItem方法中为BNRItem对象的属性设置默认值。注意,为了让编译器知道BNRNextItemValuePrefsKey常量,必须先在BNRItemStore.m顶部导入BNRAppDelegate.h。

- (BNRItem *)createItem

{

double order;

if (_allItems.count == 0) {

order = 1.0;

} else {

order = [[self.privateItems lastObject] orderingValue] + 1.0;

}

BNRItem *item =

[NSEntityDescription insertNewObjectForEntityForName:@”BNRItem“

inManagedObjectContext:self.context];

item.orderingValue = order;

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

item.valueInDollars = [defaults integerForKey:BNRNextItemValuePrefsKey];

item.itemName = [defaults objectForKey:BNRNextItemNamePrefsKey];

// 查看NSUserDefaults中存储了哪些数据

NSLog(@”defaults = %@“, [defaults dictionaryRepresentation]);

[self.privateItems addObject:item];

return item;

}

NSUserDefaults提供了若干简便方法,可以直接存取某些常用类型的值,例如以上代码中的integerForKey:。其他还有float、double、BOOL和NSURL等。以下两行代码的效果是相同的:

item.valueInDollars = [defaults integerForKey:BNRNextItemValuePrefsKey];

item.valueInDollars =

[[defaults objectForKey:BNRNextItemValuePrefsKey] intValue];

修改用户偏好设置

为应用提供修改用户偏好设置的界面很简单,可以在应用内创建相应的视图控制器,也可以为应用创建设置束,但是记录用户的使用习惯有一定的技巧,需要考虑应用特定的使用场景并推测用户的下一步操作。例如,假设用户设置了某个BNRItem对象的价值是100元,那么,用户可能将下一个BNRItem对象的价值也设置为100元。像这类用户使用信息就可以存入NSUserDefaults,方便用户再次使用。

打开BNRDetailViewController.m,导入BNRAppDelegate.h,然后修改viewWill- Disappear:,代码如下:

- (void)viewWillDisappear:(BOOL)animated

{

[super viewWillDisappear:animated];

[self.view endEditing:YES];

BNRItem *item = self.item;

item.itemName = self.nameField.text;

item.serialNumber = self.serialNumberField.text;

int newValue = [self.valueField.text intValue];

// 比较valueInDollars属性与valueField中的新值,判断是否有改动

if (newValue != item.valueInDollars) {

// 如果有改动,将新值赋给valueInDollars属性

item.valueInDollars = newValue;

// 将新值存入NSUserDefaults

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

[defaults setInteger:newValue

forKey:BNRNextItemValuePrefsKey];

}

item.valueInDollars = [self.valueField.text intValue];

}

构建并运行应用,首先创建一个名为”Coffee Cup“、价值为75元的BNRItem对象。然后创建第二个BNRItem对象,这时对象的默认价值也为75元。

同时,控制台中会输出NSUserDefaults中存储的所有数据。其中,大部分数据的键都是NSGlobalDomain。NSGlobalDomain保存了整个设备的用户偏好设置,例如语言与地区。再看NextItemName,由于应用并没有设置NextItemName的值,因此NSUserDefaults会读取NextItemName的工厂设置。工厂设置的值存放在NSUserDefaults的注册域(registration domain)中。相反,由于现在已经设置了NextItemValue的值,因此NSUserDefaults会读取应用域(application domain)中的值。对于Homepwner来说,应用域的域名是com.bignerdranch.Homepwner。

默认情况下,应用域是空的,没有键也没有值。当应用第一次设置某项用户偏好设置的值时,相应的值会通过指定的键加入应用域。当通过NSUserDefaults获取某项用户偏好设置的值时,NSUserDefaults会先在应用域中查找,如果找到了值,NSUserDefaults就会返回这个值。如果没有找到,NSUserDefaults就会在注册域中查找并返回默认值。

另外,在用户偏好设置较多的应用中,可能需要提供一个”还原默认设置“的按钮,以便将所有用户偏好设置都恢复到默认值。可以通过NSUserDefaults的实例方法removeObjectForKey:删除某个键对应的用户偏好设置。