在Singleton中访问Swift Dictionary Value时崩溃

时间:2015-04-03 19:50:43

标签: ios swift dictionary singleton

我有一个简单的类,用于跟踪字典中各种应用功能的使用情况。当应用程序发送到后台时,字典将保存到NSUserDefaults,并在首次启动应用程序时从NSUserDefaults读取。在向字典添加一些使用密钥后,发送到后台,然后重新打开并写入它,我得到一个错误的访问错误。

字典应该是可写的,我在从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(从类方法调用的访问器方法)写入Dictionary时发生崩溃

    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,所以它是Swift 1.1。我考虑过一个线程问题,例如多个读者/编写者,但考虑到我的代码正在做什么,这没有意义,而且我编写了一个多个读者/单个编写器实现,但没有帮助。字典似乎在我的应用程序的其他地方工作正常,我不确定我在这里做的不同/不好。

1 个答案:

答案 0 :(得分:1)

我已经能够通过在appDelegate.applicationWillEnterForeground()方法中调用UsageMgr read()方法来消除崩溃。 read()分配新的使用字典并从NSUserDefaults读取以前的值。

但我对此修复不满意。显然,当应用程序进入后台时,ARC正在发布我的使用字典,而这并不是我对ARC应该如何工作的理解。它肯定不是它在我的客观C应用程序中的工作方式,其中许多已在后台运行(同时使用后台提取,位置服务等)。自动发布池应该仍然存在,如果我对这些对象(包括Singleton)有全局引用,我不认为它们应该被释放。但也许我误解了一些关于ARC的事情或Swift如何实现它。