iOS OC NSUserDefaults
iOS OC NSUserDefaults文章目录iOS OC NSUserDefaults一、NSUserDefaults 到底用来干什么二、使用指南2.1 八大类型 存储方法2.2 八大类型 读取方法2.3 删除数据2.4 拓展方法三、数组 / 字典 进阶操作3.1 搜索历史累加存储动态新增、去重、限制10条3.2 清空搜索历史3.3 字典局部更新不用整体覆盖四、自定义 Model 存储4.1 模型协议配置4.2 模型存储 读取代码五、高频场景场景1判断首次启动 展示引导页场景2用户登录状态保存 退出登录清空六、项目避坑坑1读取空值不容错页面空数据UI错乱坑2Key 硬编码拼写错误、重复覆盖坑3存 nil 等于删除数据坑4数组字典嵌套自定义对象直接闪退坑5循环频繁 set 数据造成卡顿坑6重要数据不同步闪退丢失数据七、完整工具类NSUserDefaultsTool.hNSUserDefaultsTool.m工具类项目调用示例一、NSUserDefaults 到底用来干什么所有小体量、非敏感、配置型、标记型数据全部用 NSUserDefaults。项目标准使用场景用户登录状态、游客模式状态App 深色/浅色/跟随系统主题是否首次启动、是否展示过引导页弹窗是否已展示、功能新手提示是否关闭用户偏好设置字体、音量、自动播放、静音搜索历史、筛选条件、上次选中状态环境切换标记测试/生产、版本更新记录权限弹窗不再提示标记项目禁止场景密码等敏感数据大量数据二、使用指南先统一获取单例项目唯一标准写法禁止 alloc initNSUserDefaults*defaults[NSUserDefaults standardUserDefaults];2.1 八大类型 存储方法// 1. 字符串存储[defaults setObject:开发者forKey:user_nickname];// 2. 整型存储[defaults setInteger:100forKey:user_level];// 3. 浮点型存储[defaults setFloat:0.8fforKey:app_volume];// 4. 双精度存储[defaults setDouble:3.1415926forKey:app_config_num];// 5. 布尔值存储[defaults setBool:YES forKey:is_dark_mode];// 6. 数组存储[defaults setObject:[OC,Swift,iOS]forKey:search_history];// 7. 字典存储[defaults setObject:{font:15,autoPlay:1}forKey:app_ui_config];// 8. 日期存储[defaults setObject:[NSDate date]forKey:last_login_time];// 重要数据强制落盘[defaults synchronize];2.2 八大类型 读取方法// 字符串读取NSString*nickName[defaults stringForKey:user_nickname];// 整型读取NSInteger level[defaults integerForKey:user_level];// 浮点读取floatvolume[defaults floatForKey:app_volume];// 双精度读取doubleconfigNum[defaults doubleForKey:app_config_num];// 布尔读取BOOL isDark[defaults boolForKey:is_dark_mode];// 数组读取NSArray*historyArr[defaults arrayForKey:search_history];// 字典读取NSDictionary*uiConfig[defaults dictionaryForKey:app_ui_config];// 日期读取NSDate*lastLoginDate[defaults objectForKey:last_login_time];2.3 删除数据// 1. 删除单个指定Key[defaults removeObjectForKey:user_nickname];// 2. 清空当前App所有UserDefaults数据NSString*bundleID[[NSBundle mainBundle]bundleIdentifier];[defaults removePersistentDomainForName:bundleID];[defaults synchronize];2.4 拓展方法// 判断某个Key是否存在-(BOOL)UD_KeyExist:(NSString*)key{return[[NSUserDefaults standardUserDefaults]objectForKey:key]!nil;}// 安全读取字符串空值容错返回空字符串不返回nil-(NSString*)UD_GetString:(NSString*)key{NSString*str[[NSUserDefaults standardUserDefaults]stringForKey:key];returnstr?str:;}// 安全读取数组-(NSArray*)UD_GetArray:(NSString*)key{NSArray*arr[[NSUserDefaults standardUserDefaults]arrayForKey:key];returnarr?arr:[];}// 安全读取字典空值返回空字典-(NSDictionary*)UD_GetDict:(NSString*)key{NSDictionary*dict[[NSUserDefaults standardUserDefaults]dictionaryForKey:key];returndict?dict:{};}三、数组 / 字典 进阶操作3.1 搜索历史累加存储动态新增、去重、限制10条这是几乎所有App都有的功能完整可直接复用代码-(void)saveSearchHistory:(NSString*)keyword{if(!keyword||keyword.length0)return;NSUserDefaults*defaults[NSUserDefaults standardUserDefaults];NSMutableArray*historyArr[[defaults arrayForKey:search_history]mutableCopy];// 容错首次为空初始化if(!historyArr){historyArr[NSMutableArray array];}// 去重存在则先删除旧的if([historyArr containsObject:keyword]){[historyArr removeObject:keyword];}// 头部插入最新数据[historyArr insertObject:keyword atIndex:0];// 限制最大10条if(historyArr.count10){[historyArr removeLastObject];}// 重新存储[defaults setObject:historyArr forKey:search_history];[defaults synchronize];}3.2 清空搜索历史-(void)clearSearchHistory{NSUserDefaults*defaults[NSUserDefaults standardUserDefaults];[defaults removeObjectForKey:search_history];[defaults synchronize];}3.3 字典局部更新不用整体覆盖NSUserDefaults*defaults[NSUserDefaults standardUserDefaults];NSMutableDictionary*configDict[[defaults dictionaryForKey:app_ui_config]mutableCopy];if(!configDict)configDict[NSMutableDictionary dictionary];// 只更新字体大小其他配置保留configDict[font]16;[defaults setObject:configDict forKey:app_ui_config];[defaults synchronize];四、自定义 Model 存储4.1 模型协议配置// UserConfig.h#importFoundation/Foundation.hinterfaceUserConfig:NSObjectNSCodingproperty(nonatomic,copy)NSString*nickName;property(nonatomic,assign)NSInteger userType;property(nonatomic,assign)BOOL autoPlay;end// UserConfig.m#importUserConfig.himplementationUserConfig-(void)encodeWithCoder:(NSCoder*)coder{[coder encodeObject:self.nickName forKey:nickName];[coder encodeInteger:self.userType forKey:userType];[coder encodeBool:self.autoPlay forKey:autoPlay];}-(instancetype)initWithCoder:(NSCoder*)decoder{if(self[superinit]){_nickName[decoder decodeObjectForKey:nickName];_userType[decoder decodeIntegerForKey:userType];_autoPlay[decoder decodeBoolForKey:autoPlay];}returnself;}end4.2 模型存储 读取代码// 存储模型UserConfig*config[[UserConfig alloc]init];config.nickNameiOS开发者;config.userType1;config.autoPlayYES;NSData*configData[NSKeyedArchiver archivedDataWithRootObject:config requiringSecureCoding:NO error:nil];[[NSUserDefaults standardUserDefaults]setObject:configData forKey:user_config];[[NSUserDefaults standardUserDefaults]synchronize];// 读取模型NSData*data[[NSUserDefaults standardUserDefaults]dataForKey:user_config];UserConfig*userConfig[NSKeyedUnarchiver unarchivedObjectOfClass:[UserConfig class]fromData:data error:nil];五、高频场景场景1判断首次启动 展示引导页NSUserDefaults*defaults[NSUserDefaults standardUserDefaults];BOOL isFirst[defaults boolForKey:app_first_launch];if(!isFirst){// 展示引导页[defaults setBool:YES forKey:app_first_launch];[defaults synchronize];}else{// 直接进入主页}场景2用户登录状态保存 退出登录清空// 登录成功保存[defaults setBool:YES forKey:user_login_status];[defaults setObject:20260607forKey:user_login_time];// 退出登录清空[defaults removeObjectForKey:user_login_status];[defaults removeObjectForKey:user_login_time];[defaults synchronize];六、项目避坑坑1读取空值不容错页面空数据UI错乱问题读取nil字符串、nil数组直接赋值给UI会导致闪退、布局错乱。解决使用上面封装的安全读取方法空值返回空字符串/空数组。坑2Key 硬编码拼写错误、重复覆盖问题多处写死字符串key后期维护爆炸极易覆盖数据。解决全局宏定义统一管理所有Key。#definekAppFirstLaunchapp_first_launch#definekUserLoginStatususer_login_status#definekAppDarkModeapp_dark_mode坑3存 nil 等于删除数据很多人误以为可以存空值实际直接删除Key导致下次读取默认值。[defaults setObject:nil forKey:nickname];// 直接删除key坑4数组字典嵌套自定义对象直接闪退容器内部只能存原生类型嵌套Model必崩必须归档后再存储。坑5循环频繁 set 数据造成卡顿循环内频繁读写UD触发多次内存刷新UI卡顿。解决方案循环结束后统一存储、统一同步。坑6重要数据不同步闪退丢失数据状态类、登录类、配置类重要数据必须手动 synchronize防止系统未自动同步导致丢失。七、完整工具类NSUserDefaultsTool.h#importFoundation/Foundation.hinterfaceNSUserDefaultsTool:NSObject/// 单例(instancetype)shareTool;/// 通用存储-(void)saveValue:(id)value forKey:(NSString*)key;/// 通用读取-(id)getValueForKey:(NSString*)key;/// 删除单个-(void)removeKey:(NSString*)key;/// 清空全部-(void)clearAll;/// 安全读取字符串-(NSString*)getStringForKey:(NSString*)key;/// 安全读取数组-(NSArray*)getArrayForKey:(NSString*)key;/// 安全读取字典-(NSDictionary*)getDictForKey:(NSString*)key;/// 读取布尔值-(BOOL)getBoolForKey:(NSString*)key;/// 读取整型-(NSInteger)getIntegerForKey:(NSString*)key;/// 存储自定义Model归档-(void)saveModel:(id)model forKey:(NSString*)key;/// 读取自定义Model解档-(id)getModelWithClass:(Class)cls forKey:(NSString*)key;endNSUserDefaultsTool.m#importNSUserDefaultsTool.himplementationNSUserDefaultsTool(instancetype)shareTool{staticNSUserDefaultsTool*tool;staticdispatch_once_t onceToken;dispatch_once(onceToken,^{tool[[selfalloc]init];});returntool;}-(void)saveValue:(id)value forKey:(NSString*)key{if(!key)return;NSUserDefaults*defaults[NSUserDefaults standardUserDefaults];if(value){[defaults setObject:value forKey:key];}else{[defaults removeObjectForKey:key];}[defaults synchronize];}-(id)getValueForKey:(NSString*)key{if(!key)returnnil;return[[NSUserDefaults standardUserDefaults]objectForKey:key];}-(void)removeKey:(NSString*)key{if(!key)return;[[NSUserDefaults standardUserDefaults]removeObjectForKey:key];[[NSUserDefaults standardUserDefaults]synchronize];}-(void)clearAll{NSString*bundleID[[NSBundle mainBundle]bundleIdentifier];[[NSUserDefaults standardUserDefaults]removePersistentDomainForName:bundleID];[[NSUserDefaults standardUserDefaults]synchronize];}-(NSString*)getStringForKey:(NSString*)key{NSString*str[[NSUserDefaults standardUserDefaults]stringForKey:key];returnstr?str:;}-(NSArray*)getArrayForKey:(NSString*)key{NSArray*arr[[NSUserDefaults standardUserDefaults]arrayForKey:key];returnarr?arr:[];}-(NSDictionary*)getDictForKey:(NSString*)key{NSDictionary*dict[[NSUserDefaults standardUserDefaults]dictionaryForKey:key];returndict?dict:{};}-(BOOL)getBoolForKey:(NSString*)key{return[[NSUserDefaults standardUserDefaults]boolForKey:key];}-(NSInteger)getIntegerForKey:(NSString*)key{return[[NSUserDefaults standardUserDefaults]integerForKey:key];}-(void)saveModel:(id)model forKey:(NSString*)key{if(!model||!key)return;NSData*data[NSKeyedArchiver archivedDataWithRootObject:model requiringSecureCoding:NO error:nil];[selfsaveValue:data forKey:key];}-(id)getModelWithClass:(Class)cls forKey:(NSString*)key{NSData*data[selfgetValueForKey:key];if(!data)returnnil;return[NSKeyedUnarchiver unarchivedObjectOfClass:cls fromData:data error:nil];}end工具类项目调用示例// 存储字符串[[NSUserDefaultsTool shareTool]saveValue:测试forKey:test_str];// 安全读取字符串NSString*str[[NSUserDefaultsTool shareTool]getStringForKey:test_str];// 存储Model[[NSUserDefaultsTool shareTool]saveModel:userConfig forKey:user_config];// 读取ModelUserConfig*config[[NSUserDefaultsTool shareTool]getModelWithClass:[UserConfig class]forKey:user_config];