2015-04-03 74 views
1

我有一個簡單的類,用於跟蹤字典中各種應用程序功能的使用情況。當App被髮送到後臺時,字典被保存到NSUserDefaults,並且當App第一次啓動時從NSUserDefaults讀取。在向字典添加一些使用密鑰後,發送到後臺,然後重新打開並寫入它,我得到一個錯誤的訪問錯誤。Crash訪問Singleton中的Swift字典值

該字典應該是可寫的,我從NSUserDefaults讀取時重新分配一個新的字典,並將保存的使用密鑰/對象添加到它。在我編寫時,鍵和對象都是有效的(對於鍵,對象是[String:String]),就像我的類對象和字典本身一樣。我確信我在這裏做了一些愚蠢的事情,但無法弄清楚什麼。

以下是帶有重要方法的類,包括Singleton實現。

enum UsageType: Int {case ActivationHelp = 0, FullAccessHelp, ContactUs, PrivacyLink} 

func usageTypeKey(usage :UsageType) -> String { 
    switch usage { 
    case .ActivationHelp: 
     return "Activation" 
    case .FullAccessHelp: 
     return "FullAccess" 
    case .ContactUs: 
     return "ContactUs" 
    case .PrivacyLink: 
     return "PrivacyLink" 
    } 
} 

class UsageMgr { 
    var usageDb = ["default key": "default value"] 
    private let formatter : NSDateFormatter? 

    //--------------------------------- Init -----------------------------------  
    init() { 
     formatter = NSDateFormatter() 
     formatter?.dateStyle = .MediumStyle 
     formatter?.timeStyle = .MediumStyle 
     self.read() 
    } 

    //--------------------------------- Singletons ----------------------------------- 
    class var sharedInstance : UsageMgr { 
     struct Singleton { 
      static let instance = UsageMgr() 
     } 
     let existingInstance = Singleton.instance 
     return existingInstance 
    } 

    class func markUsed(usage : UsageType) { 
     let mgr = UsageMgr.sharedInstance 
     mgr.markUsed(usage) 
    } 

    //--------------------------------- Accessors ------------------------------ 
    func markUsed(usage : UsageType) { 
     let typeKey = usageTypeKey(usage) 
     let now = NSDate() 
     let dateString = self.formatter?.stringFromDate(now) 
     if let date = dateString { 
      self.usageDb[typeKey] = date 
     } 
    } 

    func saveDefaults() { 
     let defaults = NSUserDefaults.standardUserDefaults() 
     defaults.setObject(usageDb, forKey: "Usage2") 
     defaults.synchronize() 
     } 

    func read() { 
     // *** Have to reallocate every time we are re-opened, not sure why 
     // Appears usageDb is being freed by ARC 
     self.usageDb = [String: String]() 
     let defaults = NSUserDefaults.standardUserDefaults() 
     let defaultsUsageOpt = defaults.objectForKey("Usage2") as [String : String]? 
     if let usageList = defaultsUsageOpt { 
      for (key, dateString) in usageList { 
       usageDb[key] = dateString 
      } 
     } 
    } 
} 

的碰撞的方法寫入到詞典時,會發生markUsed就行

self.usageDb[typeKey] = date 

確切的錯誤是EXC_BAD_ACCESS在我的代碼行(從類方法調用訪問方法),但線程方法堆棧的底部在「swift_unknownRelease」處結束,這意味着我的字典中的鍵/對象以某種方式被釋放。但是我創建了對我的AppDelegate中Singleton和字典的引用,並且崩潰仍然發生。

調試器告訴我一切都在崩潰點

(lldb) po usageDb 
{[0] = (key = "Activation", value = "Mar 25, 2015, 2:35:49 PM") 
    [1] = (key = "PrivacyLink", value = "Mar 29, 2015, 8:50:16 PM") 
    [2] = (key = "ContactUs", value = "Apr 3, 2015, 12:24:39 PM") 
    [3] = (key = "FullAccess", value = "Apr 3, 2015, 12:24:49 PM") 
} 
(lldb) po typeKey 
"FullAccess" 

(lldb) po date 
"Apr 3, 2015, 12:24:59 PM" 

(lldb) po self 
0x0000000178039180 
{ 
    usageDb = { 
    [0] = (key = "Activation", value = "Mar 25, 2015, 2:35:49 PM") 
    [1] = (key = "PrivacyLink", value = "Mar 29, 2015, 8:50:16 PM") 
    [2] = (key = "ContactUs", value = "Apr 3, 2015, 12:24:39 PM") 
    [3] = (key = "FullAccess", value = "Apr 3, 2015, 12:24:49 PM") 
    } 
    formatter = Some { 
    Some = 0x0000000178056da0 { 
     Foundation.NSFormatter = { 
     ObjectiveC.NSObject = {} 
     } 
    } 
    } 
} 

這是Xcode的6.2潔淨,所以它的雨燕1.1。我已經考慮過一個線程問題,比如多個讀者/作者,但是在我的代碼正在做什麼時沒有意義,並且我寫了一個多讀/單編寫器實現,這沒有幫助。字典似乎在我的應用程序的其他地方工作正常,我不知道我在這裏做什麼是不同/不好。

+0

確切的崩潰是「EXC_BAD_ACCESS」 – 2015-04-03 19:55:30

+0

代碼的某些部分未定義,例如類UsageType。我改變了一點,運行它,它的工作原理。您想添加如何使用UsageMgr嗎?同樣在markUsed()中,你確定typeKey不是零嗎? – TimeString 2015-04-03 20:12:55

+0

TimeString,感謝您指出監督,添加UsageType/UsageTypeKey()定義。當用戶使用/看到功能/幫助屏幕時,會調用UsageMgr.markUsed()以記錄使用情況。第一次調用自動進入Singleton類並調用UsageMgr.read()從磁盤讀取先前的版本。 UsageMgr.save()從我的AppDelegate.applicationDidEnterBackground中調用。調試程序指出typeKey是在崩潰點處的字符串「FullAccess」。 – 2015-04-03 21:58:53

回答

1

我已經能夠通過調用我的appDelegate.applicationWillEnterForeground()方法中的UsageMgr read()方法來消除崩潰。 read()分配一個新的用法字典並從NSUserDefaults讀取以前的值。

但我對此修復程序並不滿意。顯然,當應用程序進入後臺時,ARC會發布我的用法詞典,這不是我對ARC如何工作的理解。這當然不是它在我的客觀C應用程序中的工作方式,其中許多已經在後臺運行(使用後臺提取,位置服務等)。自動釋放池應該仍然存在,如果我有這些對象的全局引用(包括Singleton),我不認爲它們應該被釋放。但是也許我誤解了一些關於ARC或者Swift如何實現它的東西。