美文网首页ios系统兼容
NSUserDefaults的使用

NSUserDefaults的使用

作者: 想聽丿伱說衹愛我 | 来源:发表于2020-09-04 10:45 被阅读0次

版本:iOS13.6

一、简介

NSUserDefaults是一种存储轻量化数据的方案,系统会将存储的内容以plist文件的形式保存在沙盒中,路径为Library/Preferences/xxx.plist,xxx为项目的Bundle Identifier。
可保存的数据类型为NSString NSData NSNumber NSDate NSArray NSDictionary,若想保存某些model,可使用yyModel将之转化成json再将其存入。

二、NSUserDefaults API

@interface NSUserDefaults : NSObject 

//返回全局实例 只读
@property (class, readonly, strong) NSUserDefaults *standardUserDefaults;
//将存储的数据全部删除
//而且KVO观察者将不会再观察数据的变化
+ (void)resetStandardUserDefaults;

//相当于initWithSuiteName:nil
- (instancetype)init;
//预创建一个新的plist,并返回它的实例,在沙盒中的路径为Library/Preferences/suitename.plist
//但只有向里面存储数据后才会实际创建该plist
//当initWithSuiteName:nil时会返回全局实例
//在该方法返回的实例中保存的数据可在不同的app中共享
//详见第三节
- (nullable instancetype)initWithSuiteName:(nullable NSString *)suitename;
//已弃用
- (nullable id)initWithUser:(NSString *)username API_DEPRECATED(ios(2.0,7.0));

//获取对应密钥的数据 
//数据 类型为NSString NSData NSNumber NSDate NSArray NSDictionary
- (nullable id)objectForKey:(NSString *)defaultName;
//为对应密钥存储一个数据 
//该数据是异步存储的,可通过synchronize使数据立即同步存储
//数据 类型为NSString NSData NSNumber NSDate NSArray NSDictionary
//若value = nil ,则移除对应密钥保存的数据 
- (void)setObject:(nullable id)value forKey:(NSString *)defaultName;
//移除对应密钥保存的数据
//相当于setObject:nil forKey:defaultName
- (void)removeObjectForKey:(NSString *)defaultName;

//获取对应密钥保存的NSString类型数据
//若数据为NSNumber,可自动转换为字符串;若为其他类型,返回nil
- (nullable NSString *)stringForKey:(NSString *)defaultName;
//获取对应密钥保存的NSArray类型数据
//若为其他类型,返回nil
- (nullable NSArray *)arrayForKey:(NSString *)defaultName;
//获取对应密钥保存的NSDictionary类型数据
//若为其他类型,返回nil
- (nullable NSDictionary<NSString *, id> *)dictionaryForKey:(NSString *)defaultName;
//获取对应密钥保存的NSData类型数据
//若为其他类型,返回nil
- (nullable NSData *)dataForKey:(NSString *)defaultName;
//获取对应密钥保存的NSArray<NSString *>类型数据
//若为其他类型,返回nil
//与stringForKey不同的是,若数组中的数据为NSNumber,也将返回nil
- (nullable NSArray<NSString *> *)stringArrayForKey:(NSString *)defaultName;

//获取对应密钥保存的数据,并将其转换成NSInteger
//若为NSNumber,可直接转换成功
//若为NSString,若能转换成功则返回对应的值,否则返回0
//若为布尔值,YES则返回1,NO则返回0
//其他情况则返回0
- (NSInteger)integerForKey:(NSString *)defaultName;
//获取对应密钥保存的数据,并将其转换成float
//与integerForKey类似,不同之处在于当为布尔值时,不会转换
- (float)floatForKey:(NSString *)defaultName;
//获取对应密钥保存的数据,并将其转换成double
//与integerForKey类似,不同之处在于当为布尔值时,不会转换
- (double)doubleForKey:(NSString *)defaultName;
//获取对应密钥保存的数据,并将其转换成BOOL
//若为NSNumber,@(0)则返回NO,其他则返回YES
//若为NSString,1或YES则返回YES,其他则返回NO
//其他情况则返回NO
- (BOOL)boolForKey:(NSString *)defaultName;
//获取对应密钥保存的NSURL类型数据
//若为NSString,则会将该路径转换成NSURL
//若是通过-setURL:forKey:保存的数据,则返回对应的NSURL
//若该值不存在或无法转换为NSURL,则返回nil
- (nullable NSURL *)URLForKey:(NSString *)defaultName;

//为对应密钥存储一个NSInteger数据 
//NSIntege通过NSNumber来存储,相当于setObject:@(value) forKey:
- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName;
//为对应密钥存储一个float数据 
//float通过NSNumber来存储,相当于setObject:@(value) forKey:
- (void)setFloat:(float)value forKey:(NSString *)defaultName;
//为对应密钥存储一个double数据 
//double通过NSNumber来存储,相当于setObject:@(value) forKey:
- (void)setDouble:(double)value forKey:(NSString *)defaultName;
//为对应密钥存储一个BOOL数据 
//double通过NSNumber来存储,相当于setObject:@(value) forKey:
- (void)setBool:(BOOL)value forKey:(NSString *)defaultName;
//为对应密钥存储一个NSURL数据 
//NSURL会归档为NSData来存储,可通过URLForKey来获取该NSURL
- (void)setURL:(nullable NSURL *)url forKey:(NSString *)defaultName;

//注册默认值,默认值会保存在搜索列表中的最后一项NSRegistrationDomain域中
//当未查询出对应密钥的数据后,会继续在默认值中查询,若有查询出结果,则使用该默认值返回
//默认值只对该应用程序有效,不会共享。
//详见下面的例1
- (void)registerDefaults:(NSDictionary<NSString *, id> *)registrationDictionary;

//给当前的NSUserDefaults添加一个子搜索列表suiteName
//搜索数据时,会按照 本身的列表--子搜索列表-注册的默认值列表 的顺序搜索
//详见下面的例2
- (void)addSuiteNamed:(NSString *)suiteName;
//从当前的NSUserDefaults移除已添加的子搜索列表suiteName
- (void)removeSuiteNamed:(NSString *)suiteName;

//返回所有已保存数据
//里面有一些系统添加的数据,可以修改,但无法删除
//当对这些数据调用removeObjectForKey时,会使该值变成初始值
//详见下面的例3
- (NSDictionary<NSString *, id> *)dictionaryRepresentation;

//返回易失性域的名字的数组 只读
//易失性域不会添加到任何搜索列表中,也不会持久保存,重启app后数据会重置。
//并且对其他应用程序不可见。不建议使用它们
//详见下面的例4
@property (readonly, copy) NSArray<NSString *> *volatileDomainNames;
//获取对应易失性域的数据
- (NSDictionary<NSString *, id> *)volatileDomainForName:(NSString *)domainName;
//给对应易失性域设置数据 
- (void)setVolatileDomain:(NSDictionary<NSString *, id> *)domain forName:(NSString *)domainName;
//移除对应域名的易失性域
- (void)removeVolatileDomainForName:(NSString *)domainName;

//返回持久性域的名字的数组 已废弃
- (NSArray *)persistentDomainNames API_DEPRECATED(ios(2.0,7.0));
//获取对应持久性域的数据
//详见下面的例5
- (nullable NSDictionary<NSString *, id> *)persistentDomainForName:(NSString *)domainName;
//给对应持久性域设置数据 
- (void)setPersistentDomain:(NSDictionary<NSString *, id> *)domain forName:(NSString *)domainName;
//移除对应域名的持久性域
- (void)removePersistentDomainForName:(NSString *)domainName;

//立即同步存储数据
//因为数据保存都是异步的,通过该方法将会同步存储
//若要保存的数据量过大时,可能造成卡顿,要慎用。
//不建议使用,该方法将在不久后被弃用。
- (BOOL)synchronize;

//判断某个密钥是否由管理员管理
- (BOOL)objectIsForcedForKey:(NSString *)key;

//判断domain域中某个密钥是否由管理员管理
- (BOOL)objectIsForcedForKey:(NSString *)key inDomain:(NSString *)domain;

@end
  • 例1
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    //移除key的数据
    [defaults removeObjectForKey:@"key"];
    NSString *value = [defaults objectForKey:@"key"];
    NSLog(@"value = %@", value);
    //注册默认值
    [defaults registerDefaults:@{@"key":@"defaults"}];
    value = [defaults objectForKey:@"key"];
    NSLog(@"value = %@", value);
    //为key设置数据 
    [defaults setObject:@"test" forKey:@"key"];
    value = [defaults objectForKey:@"key"];
    NSLog(@"value = %@", value);
输出:
value = (null)
value = defaults
value = test
说明:
因为key中保存的数据已经被删除了,所以value = (null)
注册了key的默认值后,因为key中仍没有数据,会使用默认值的数据,所以value = defaults
在为key设置数据后,会使用已设置的数据,所以value = test
  • 例2
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSUserDefaults *nameDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"nameDefaults"];
    [nameDefaults setObject:@"liu" forKey:@"name"];
    NSLog(@"name = %@", [defaults objectForKey:@"name"]);
    [defaults addSuiteNamed:@"nameDefaults"];
    NSLog(@"name = %@", [defaults objectForKey:@"name"]);
    [defaults removeSuiteNamed:@"nameDefaults"];
    NSLog(@"name = %@", [defaults objectForKey:@"name"]);
输出:
name = (null)
name = liu
name = (null)
说明:
因为defaults中没有name的数据,所有name = (null)
当defaults添加了子搜索列表nameDefaults后,而nameDefaults中有name的数据,所以name = liu
当defaults移除了nameDefaults后,则会重新name = (null)
  • 例3
    NSDictionary *dict = [defaults dictionaryRepresentation];
    NSLog(@"%@", dict);
    //修改AppleLanguages的数据,此方法可以将app的语言变为中文
    [defaults setObject:@[@"zh-Hans-CN"] forKey:@"AppleLanguages"];
    NSLog(@"%@", [defaults objectForKey:@"AppleLanguages"]);
    //移除AppleLanguages的数据,会重置为初始值
    [defaults setObject:nil forKey:@"AppleLanguages"];
    NSLog(@"%@", [defaults objectForKey:@"AppleLanguages"]);
输出:
{
    AKLastIDMSEnvironment = 0;
    AddingEmojiKeybordHandled = 1;
    AppleITunesStoreItemKinds =     (
        podcast,
        artist,
        "itunes-u",
        booklet,
        document,
        movie,
        eBook,
        software,
        "software-update",
        "podcast-episode"
    );
    AppleKeyboards =     (
        "zh_Hans-Pinyin@sw=Pinyin-Simplified;hw=Automatic",
        "en_US@sw=QWERTY;hw=Automatic",
        "ja_JP-Kana@sw=Kana;hw=Automatic",
        "en_US@sw=QWERTY;hw=Automatic"
    );
    AppleKeyboardsExpanded = 1;
    AppleLanguages =     (
        "zh-Hans-CN",
        "en-CN",
        "ja-JP"
    );
    AppleLanguagesSchemaVersion = 1001;
    AppleLocale = "zh_CN";
    ApplePasscodeKeyboards =     (
        "en_US",
        emoji
    );
    CarCapabilities =     {
        CarCapabilitiesDefaultIdentifier =         {
            CRCapabilitiesDisabledFeatureKey = 0;
            CRCapabilitiesUserInterfaceStyleKey = 2;
            CRCapabilitiesVersionKey = "";
            CapabilitiesDashboardRoundedCornersKey = "{{13, 0}, {0, 0}}";
            CapabilitiesNowPlayingAlbumArtKey = 2;
            CapabilitiesViewAreaInsetKey = "{{0, 0}, {0, 0}}";
        };
    };
    NSInterfaceStyle = macintosh;
    NSLanguages =     (
        "zh-Hans-CN",
        "en-CN",
        "ja-JP",
        en
    );
    PKKeychainVersionKey = 7;
    key = test;
}
(
    "zh-Hans-CN"
)
(
    "zh-Hans-CN",
    "en-CN",
    "ja-JP"
)
说明:
其中的key = test 为自已设置的数据,其他的都是系统自带的。
可见当使用setObject:forKey:后,成功将AppleLanguages的值改成了("zh-Hans-CN")
当删除AppleLanguages的值后,AppleLanguages的值被重置为
(
    "zh-Hans-CN",
    "en-CN",
    "ja-JP"
)
  • 例4
    //获取域名的数组
    NSArray *array = [defaults volatileDomainNames];
    NSLog(@"%@", array);
    //获取对应域的数据
    NSDictionary *dict0 = [defaults volatileDomainForName:array[0]];
    NSDictionary *dict1 = [defaults volatileDomainForName:array[1]];
    NSLog(@"dict0 = %@\ndict1 = %@", dict0, dict1);
    //为该域设置新的数据
    [defaults setVolatileDomain:@{@"volatile":@"111"} forName:array[0]];
    dict0 = [defaults volatileDomainForName:array[0]];
    NSLog(@"%@", dict0);
    [defaults removeVolatileDomainForName:array[0]];
输出:
(
    NSRegistrationDomain,
    NSArgumentDomain
)
dict0 = {
    AppleLanguages =     (
        "zh-Hans-CN",
        "en-CN",
        "ja-JP",
        en
    );
    NSInterfaceStyle = macintosh;
    NSLanguages =     (
        "zh-Hans-CN",
        "en-CN",
        "ja-JP",
        en
    );
    key = defaults;
}
dict1 = {
}
{
    volatile = 111;
}
说明:
可看到域名有NSRegistrationDomain和NSArgumentDomain。
NSRegistrationDomain域里保存着初始数据,而NSArgumentDomain域里没有数据。
而且NSRegistrationDomain域中有key = defaults这组数据,这是之前调用registerDefaults注册的默认值。
然后通过setVolatileDomain方法为NSRegistrationDomain域设置新的数据。

NSUserDefaults的三个特殊的系统域:
这个是一个系统级别的全局的域,存储着系统配置信息。
所有应用程序共享该域,不建议修改里面的数据据,可能造成应用程序启动失败。
NSString * const NSGlobalDomain;
这个是在本应用程序内可访问的域,存储着应用程序的信息。
可在Edit Scheme--Arguments--Arguments Passed On Launch添加,格式是 -key value
NSString * const NSArgumentDomain;
这个是存放临时数据的域,通过registerDefaults注册的默认值会存入其中
NSString * const NSRegistrationDomain;

还有两个隐藏的域
应用程序域,通过setObject设置的数据会保存在这里。
Application
国际化语言域,保存着关于多语言的配置。
Languages

通常NSUserDefault的搜索顺序为
NSArgumentDomain->Application->(通过addSuiteNamed添加的Application的子域)->NSGlobalDomain->Languages->NSRegistrationDomain

  • 例5
    NSArray *arr = [defaults persistentDomainNames];
    NSLog(@"%@", arr);
    //获取对应域的数据
    NSDictionary *dict2 = [defaults persistentDomainForName:arr[0]];
    NSDictionary *dict3 = [defaults persistentDomainForName:arr[1]];
    NSLog(@"%@", dict2);
    //为该域设置新的数据
    [defaults setPersistentDomain:@{@"volatile":@"222"} forName:arr[0]];
    dict2 = [defaults persistentDomainForName:arr[0]];
    NSLog(@"%@", dict2);
    [defaults removePersistentDomainForName:arr[0]];
    dict2 = [defaults persistentDomainForName:arr[0]];
    NSLog(@"%@", dict2);
输出:
(
    nameDefaults,
    "com.asiainfo.mobile.DEMO111"
)
{
    name = liu;
}
{
    volatile = 222;
}
(null)
说明:
持久性域中有两个域,分别为com.asiainfo.mobile.DEMO111和nameDefaults。
其中com.asiainfo.mobile.DEMO111为standardUserDefaults创建的plist。
nameDefaults是在例2中通过initWithSuiteName方法创建的。
通过persistentDomainForName获取域nameDefaults的数据,为name = liu。
通过setPersistentDomain为域nameDefaults设置新的数据,为volatile = 222。
通过removePersistentDomainForName移除域nameDefaults中的所有数据

三、使用NSUserDefaults将数据在不同应用程序间共享

image.png

先按上面图片添加一个组名
然后在该项目中输入以下代码,存入一个数据

    //该plist并不会存入Library/Preferences文件夹中
    NSUserDefaults *shareDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.asiainfo.liuxu"];
    [shareDefaults setObject:@"abc123" forKey:@"shareId"];

在另一个项目中也照上面图片添加一个相同的组名
输入以下代码

    NSUserDefaults *shareDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.asiainfo.liuxu"];
    NSLog(@"%@", [shareDefaults objectForKey:@"shareId"]);

会输出abc123,说明数据已经共享。

相关文章

网友评论

    本文标题:NSUserDefaults的使用

    本文链接:https://www.haomeiwen.com/subject/xstosktx.html