因为项目里面有个切换环境
的功能,切换环境
后就会将选中的环境更新到用户偏好
里面,然后退出app
,重新启动app
就从用户偏好里面读取新的环境变量
,然后请求的新环境地址
。
之前代码类似如下:
[FJFEnvironmentManager updateEnvironmentType:type];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
exit(0);
});
+ (void)updateEnvironmentType:(FJFEnvironmentType)environmentType {
[NSUserDefaults.standardUserDefaults setValue:@(environmentType) forKey:kFJJEnvironmentTypeKey];
[NSUserDefaults.standardUserDefaults synchronize];
}
但存在有时候切换环境不成功问题,终于找到原因。
分析过程
首先从代码逻辑分析,觉得应该是没问题的,因为更新环境并保存到偏好设置,这里调用了[NSUserDefaults.standardUserDefaults synchronize];
同步方法,因此应该是不存在环境没更新的问题。
接着通过查看偏好设置的plist
文件,发现环境的更改并没有即时,存在延期情况,因此查看了synchronize
函数。
/*!
-synchronize is deprecated and will be marked with the API_DEPRECATED macro in a future release.
-synchronize blocks the calling thread until all in-progress set operations have completed. This is no longer necessary. Replacements for previous uses of -synchronize depend on what the intent of calling synchronize was. If you synchronized...
- ...before reading in order to fetch updated values: remove the synchronize call
- ...after writing in order to notify another program to read: the other program can use KVO to observe the default without needing to notify
- ...before exiting in a non-app (command line tool, agent, or daemon) process: call CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication)
- ...for any other reason: remove the synchronize call
*/
这里说synchronize
这个函数已经被弃用,在将来版本使用中将使用API_DEPRECATED
宏进行标志。
也就是说用户偏好的同步函数synchronize
不在是同步阻塞的,而是系统内部定期去更新保存的。
用户偏好本质是一个plist
文件,之所以多封装了一层,是因为多加了一层内存缓存操作,你对用户偏好的修改,会直接更新到内存缓存中,然后你立刻去读取,会直接从内存缓存中返回,然后内部在定时存储到plist
里面。
也正是因为这样,我们更换环境,退出app,然后立刻重启,可能用户偏好的plist
还没更新,导致读取到的还是以前的环境变量值。
修改方法
-
最开始的时候想直接新建一个
plist
类来存储环境变量的值,然后操作plist文件来修改环境变量的值,但这种方法一来改动量有点大,二来用plist
只存储一个环境变量有点浪费 -
最终改用
NSKeyedArchiver归档
来存储环境变量值,这样只需新增路径,改变下存储和读取方法。
网友评论