iOS 13 UserDefaults:在某些设备上启动时应用程序崩溃

Posted

技术标签:

【中文标题】iOS 13 UserDefaults:在某些设备上启动时应用程序崩溃【英文标题】:iOS 13 UserDefaults: app crash on start on some devices 【发布时间】:2019-10-16 13:12:44 【问题描述】:

应用程序在 ios 13 上在某些设备上启动时崩溃。该应用程序正在生产中,我在 Xcode Organizer 崩溃中看到了这个问题。我无法在模拟器或任何物理设备上重现此问题。

我想这与本地化有关。我使用“AppleLanguages”键并将所选语言保存为数组。我将用户默认值中的语言保存为:

static var language: Language 
    get 

        if UserDefaults.standard.bool(forKey: isLanguageSelectedKey) 
            if let languageCode = UserDefaults.standard.array(forKey: appleLanguagesKey)?.first,
                let language = Language(rawValue: languageCode as! String) 
                return language
             else 

                return Language.someLanguage
            
         else 
            return Language.someLanguage
        

    

    set 
        guard language != newValue else 
            return
        
        UserDefaults.standard.removeObject(forKey: appleLanguagesKey)
        UserDefaults.standard.synchronize()

        UserDefaults.standard.set([newValue.rawValue], forKey: appleLanguagesKey)

        UserDefaults.standard.synchronize()
    

我在 Xcode Organizer 崩溃中看到的 Stacktrace 是:

Last Exception Backtrace (0)
0   (null) in __exceptionPreprocess ()
-------------------------------------------------------
8   (null) in +[NSUserDefaults(NSUserDefaults) standardUserDefaults] ()
9   (null) in __45+[GMSx_GTMSessionFetcher fetcherUserDefaults]_block_invoke ()
10  (null) in _dispatch_client_callout ()
11  (null) in _dispatch_once_callout ()
12  (null) in +[GMSx_GTMSessionFetcher fetcherUserDefaults] ()
13  (null) in +[GMSx_GTMSessionFetcher fetchersForBackgroundSessions] ()
14  (null) in +[GMSx_GTMSessionFetcher load] ()
15  (null) in load_images ()
-------------------------------------------------------



Thread 1
0   (null) in __pthread_kill ()
-------------------------------------------------------
9   (null) in _dispatch_once_callout ()
10  (null) in +[GMSx_GTMSessionFetcher fetcherUserDefaults] ()
11  (null) in +[GMSx_GTMSessionFetcher fetchersForBackgroundSessions] ()
12  (null) in +[GMSx_GTMSessionFetcher load] ()
13  (null) in load_images ()
-------------------------------------------------------

【问题讨论】:

你可以试试没有这条线UserDefaults.standard.removeObject(forKey: appleLanguagesKey) 我认为这不会引发这种情况,因为在用户选择语言之后调用了“set”代码块,并且在此之前应用程序崩溃 设置前不需要删除key,也不要使用synchronize。苹果表示“这种方法是不必要的,不应该使用。” 你还有languageCode as! String - 你确定它是一个字符串而不是,比如说,Int? 【参考方案1】:

我没有一切,所以这里有一些假设可能无法正确解决:

static var language: Language 
get 
        if UserDefaults.standard.bool(forKey: isLanguageSelectedKey),
             let languageCode = UserDefaults.standard.array(forKey: appleLanguagesKey)?.first as? string,
             let language = Language(rawValue: languageCode) 
                return language
        
        // No language value found, so return someLanguage
        return Language.someLanguage

    
set 
    guard language != newValue else 
        return
    
    UserDefaults.standard.removeObject(forKey: appleLanguagesKey)
    UserDefaults.standard.set([newValue.rawValue], forKey: appleLanguagesKey)

做了什么?

    languageCode 现在已安全展开以避免强制转换,这可能导致崩溃 重写了 if 语句,使其更加简洁,并消除了导致 Language.someLanguage 返回的一种情况 我删除了您的 setter 中的 synchonize() 调用

【讨论】:

以上是关于iOS 13 UserDefaults:在某些设备上启动时应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在某些设备上从 iOS 应用商店安装时出错

Swift - UserDefaults 设置未保存在框架内

iOS UserDefaults 落后于保存的内容

访问令牌持久性最佳实践 (iOS)

在 UserDefaults 中保存项目数组 - iOS 12

在 iOS 14 中的主应用程序和小部件之间共享 UserDefaults