当前位置: 首页 > news >正文

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错乱
      • 坑2:Key 硬编码,拼写错误、重复覆盖
      • 坑3:存 nil 等于删除数据
      • 坑4:数组字典嵌套自定义对象,直接闪退
      • 坑5:循环频繁 set 数据,造成卡顿
      • 坑6:重要数据不同步,闪退丢失数据
    • 七、完整工具类
      • NSUserDefaultsTool.h
      • NSUserDefaultsTool.m
      • 工具类项目调用示例

一、NSUserDefaults 到底用来干什么?

所有小体量、非敏感、配置型、标记型数据,全部用 NSUserDefaults

项目标准使用场景:

  • 用户登录状态、游客模式状态
  • App 深色/浅色/跟随系统主题
  • 是否首次启动、是否展示过引导页
  • 弹窗是否已展示、功能新手提示是否关闭
  • 用户偏好设置:字体、音量、自动播放、静音
  • 搜索历史、筛选条件、上次选中状态
  • 环境切换标记(测试/生产)、版本更新记录
  • 权限弹窗不再提示标记

项目禁止场景:

  • 密码等敏感数据
  • 大量数据

二、使用指南

先统一获取单例(项目唯一标准写法,禁止 alloc init)

NSUserDefaults*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.length==0)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.count>10){[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#import<Foundation/Foundation.h>@interfaceUserConfig:NSObject<NSCoding>@property(nonatomic,copy)NSString*nickName;@property(nonatomic,assign)NSInteger userType;@property(nonatomic,assign)BOOL autoPlay;@end// UserConfig.m#import"UserConfig.h"@implementationUserConfig-(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;}@end

4.2 模型存储 & 读取代码

// 存储模型UserConfig*config=[[UserConfig alloc]init];config.nickName=@"iOS开发者";config.userType=1;config.autoPlay=YES;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:@"20260607"forKey:@"user_login_time"];// 退出登录清空[defaults removeObjectForKey:@"user_login_status"];[defaults removeObjectForKey:@"user_login_time"];[defaults synchronize];

六、项目避坑

坑1:读取空值不容错,页面空数据UI错乱

问题:读取nil字符串、nil数组,直接赋值给UI会导致闪退、布局错乱。

解决:使用上面封装的安全读取方法,空值返回空字符串/空数组。

坑2:Key 硬编码,拼写错误、重复覆盖

问题:多处写死字符串key,后期维护爆炸,极易覆盖数据。

解决:全局宏定义统一管理所有Key。

#definekAppFirstLaunch@"app_first_launch"#definekUserLoginStatus@"user_login_status"#definekAppDarkMode@"app_dark_mode"

坑3:存 nil 等于删除数据

很多人误以为可以存空值,实际直接删除Key,导致下次读取默认值。

[defaults setObject:nil forKey:@"nickname"];// 直接删除key!

坑4:数组字典嵌套自定义对象,直接闪退

容器内部只能存原生类型,嵌套Model必崩,必须归档后再存储。

坑5:循环频繁 set 数据,造成卡顿

循环内频繁读写UD,触发多次内存刷新,UI卡顿。

解决方案:循环结束后统一存储、统一同步。

坑6:重要数据不同步,闪退丢失数据

状态类、登录类、配置类重要数据,必须手动 synchronize,防止系统未自动同步导致丢失。

七、完整工具类

NSUserDefaultsTool.h

#import<Foundation/Foundation.h>@interfaceNSUserDefaultsTool: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;@end

NSUserDefaultsTool.m

#import"NSUserDefaultsTool.h"@implementationNSUserDefaultsTool+(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"];
http://www.cnnetsun.cn/news/2859751.html

相关文章:

  • 学术会议丨顶会CVPR 2026收官:从论文数据看计算机视觉的五大范式迁移
  • 微信是怎么知道你是同一个用户的?UV统计的底层秘密
  • 手把手教你用OOMMF的MIF 2.1文件构建自定义微磁模型(附完整示例解析)
  • 告别黑盒:深入解读OOMMF MIF 2.1文件,打造你的自定义微磁模拟脚本
  • LLM推荐系统中的不确定性量化与公平性优化
  • PyCharm包管理器安装失败?试试这个比官方提示更管用的“终端+降级pip”组合拳
  • SAP ABAP开发:别再只用GUID_CREATE了!新旧版本生成GUID/UUID的完整避坑指南
  • 双击就能发的圣诞网页贺卡,手机电脑都能看,带飘雪效果和可改祝福语
  • 佳能打印机出现5B00,5B02,5B04,1700,1702,1704,P07,E08这些报错就意味着打印机废墨满了,需要用软件清零了,亲测完美修复,TS3380,G3800,G3000
  • 架构师的能力——不是画图是知道每段改动对全局的连锁反应
  • 2026 抚州 GEO 精准获客避坑,掌握标准少花冤枉钱
  • 神学、艺术、科学的区别: 从不确定性的角度
  • 2026,招投标的AI时间表到了:那些还在手动搜标的企业,正在被时代甩下
  • 城配运营的“护身符”:每一单都可追溯,每一步都有凭证
  • 5 分钟上手!Hermes Agent 插件开发保姆级教程,扩展能力从此开挂
  • 机器人DSP如何精准选型:三大痛点下的国产芯片实力排名
  • 需求从一句话到可执行 Ticket,中间差一段表达整理
  • 纯亚克力浴缸知名企业
  • 3分钟掌握WorkshopDL:解锁Steam创意工坊资源的完整解决方案
  • GPU 算力瓶颈在哪?怎么榨干?万卡集群如何协同?
  • phpstorm2026版本汉化
  • 大麦网抢票脚本:用Python技术告别手动抢票的烦恼
  • i.MX 6处理器电气特性深度解析:从PLL时钟到DDR信号完整性的硬件设计指南
  • 初学者ROS2教程:创建你的第一个工作区和软件包
  • GTC泽汇:“芯片反弹提振风险偏好”
  • 2026年GrowthOSGEO优化大揭秘,背后究竟藏着怎样的提升秘诀?
  • 【CVPR 2026即插即用模块】DEGConv方向引导边缘门控卷积,适合裂缝分割、血管分割、车道线检测、电力线检测、边缘检测、医学细长结构分割、目标检测、实例分割等CV任务通用,涨点起飞!
  • 2026年,西安未央附近专业代理记账品牌大揭秘,诚信之选究竟是谁?
  • 全面解析 OpenAI Codex客户端核心功能:提升桌面端开发与自动化体验
  • 魔法森林三消Unity工程:300+关卡+特效动画+Facebook社交集成