【问题标题】:Swift - access to Dictionary of a singleton causes EXC_BAD_ACCESSSwift - 访问单例字典会导致 EXC_BAD_ACCESS
【发布时间】:2014-10-22 19:54:32
【问题描述】:

我有一个应用程序来管理一个简单的股票投资组合。除其他外,它在字典中记录所需的汇率,如下所示: [欧元美元=X:1.267548] 这个字典是一个名为 CurrencyRateStore 的单例的字典属性。

更新股票报价时,它会检查更新的汇率并使用以下代码更新字典:

CurrencyRateStore.sharedStore()[symbol] = fetchedRate.doubleValue

那叫:

subscript(index: String) -> Double? {
    get {
        return dictionary[index]
    }
    set {
        // FIXME: crashes when getting out of the app (Home button) and then relaunching it
            dictionary[index] = newValue!
            println("CurrencyRateStore - updated rate for \(index) : \(newValue!)")
    }
}

应用程序第一次启动时,它运行良好。 但是如果我退出应用程序(使用主页按钮)然后重新启动它,货币汇率会再次更新,但这一次,我在线路上得到一个 EXC_BAD_ACCESS

dictionary[index] = newValue!

这是一个截图:

[编辑] 这是调试导航器中的线程:

我尝试在没有下标的情况下更新字典,如下所示:

CurrencyRateStore.sharedStore().dictionary[symbol] = fetchedRate.doubleValue

但没有更多的成功。如果我使用函数 updateValue:forKey: 我在 Objective-C 中没有这个问题。

感谢您的帮助!

[编辑] 这是整个类CurrencyRateStore

class CurrencyRateStore {

// MARK: Singleton
class func sharedStore() -> CurrencyRateStore! {
    struct Static {
        static var instance: CurrencyRateStore?
        static var token: dispatch_once_t = 0
    }

    dispatch_once(&Static.token) {
        Static.instance = CurrencyRateStore()
    }

    return Static.instance!
}

// MARK: Properties

/** Dictionary of currency rates used by the portfolio, presented like  [ EURUSD=X : 1.3624 ] */
var dictionary = [String : Double]()

/** Returns a sorted array of all the keys on the currency rates dictionary */
var allKeys: [String] {
var keysArray = Array(dictionary.keys)
    keysArray.sort {$0 < $1}
    return keysArray
}

init() {
    if let currencyRateDictionary: AnyObject = NSKeyedUnarchiver.unarchiveObjectWithFile(currencyRateArchivePath) {
        dictionary = currencyRateDictionary as [String : Double]
    }
}

subscript(index: String) -> Double? {
    get {
        return dictionary[index]
    }
    set {
        // FIXME: crashes when getting out of the app (Home button) and then relaunching it
        // (ApplicationWillEnterForeground triggers updateStocks)
            dictionary[index] = newValue!
            println("CurrencyRateStore - updated rate for \(index) : \(newValue!)")
    }
}


func deleteRateForKey(key: String) {
    dictionary.removeValueForKey(key)
}


/** Removes all currency rates from the Currency rate store */
func deleteAllRates()
{
    dictionary.removeAll()
}


// MARK: Archive items in CurrencyRateStore
var currencyRateArchivePath: String { // Archive path
var documentDirectories: Array = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)

    // Get the only document directory from that list
    let documentDirectory: AnyObject = documentDirectories.first!

    return documentDirectory.stringByAppendingPathComponent("currencyRates.archive")
}

func saveChanges()-> Bool
{
    // return success or failure
    return NSKeyedArchiver.archiveRootObject(dictionary, toFile: currencyRateArchivePath)
}

}

【问题讨论】:

  • 你能发布整个错误日志吗?也许这可以帮助
  • 能否也分享CurrencyRateStore的一些相关部分?至少是单例实现,字典属性的声明
  • 但是 EXC_BAD_ACCESS 上没有日志……你的意思是,调试导航器中的线程?
  • 如果你在模拟器中运行,检查~/Library/Logs/DiagnosticReports/文件夹
  • 在模拟器中,它可以工作......只有在真正的 iPhone 6 上运行时才会崩溃......等等,我会尝试从设备中删除该应用程序,然后重新安装。

标签: swift dictionary ios8


【解决方案1】:

这在我看来像是一个并发问题。 Swift 字典不是线程安全的,从单例中使用它们可能会导致多个读取器/写入器问题。

编辑:我很确定这是真正的答案,基于给定的源/调试转储。为了纠正我写的内容,特别是 MUTABLE 字典和数组(以及 NSMutableDictionary 和 NSMutableArray)不是线程安全的,并且在从多个线程访问的单例中使用它们时会出现问题,这似乎是示例源代码正在做,或者让代码的其他部分去做。

我没有讨论 Swift 集合类线程安全性的 Apple 链接,但我很确定常识。但以下关于 Grand Central Dispatch 的教程深入讨论了这个问题以及如何使用 GCD 解决它。

http://www.raywenderlich.com/79149/grand-central-dispatch-tutorial-swift-part-1

【讨论】:

  • 现在看起来很有趣。您能否详细说明您的答案?为什么你认为从单例中使用它们会导致多个读/写问题?你从哪里得知 Swift 字典不是线程安全的,你认为 NSDictionary 是线程安全的吗?非常感谢!
  • 我觉得确实和字典有关,因为我经常在单例中使用数组,而且我从来没有遇到过这样的问题...
【解决方案2】:

错误和行本身:

dictionary[index] = newValue!

让我觉得问题是newValuenil - 错误是由强制展开引起的。 我建议设置一个断点并检查它的值,或者在添加到字典之前打印它。

此外,使用可选绑定保护该语句也不是一个坏主意:

if let value = newValue {
    dictionary[index] = value
}

因为如果值类型是可选的,它可以是nil。

【讨论】:

  • 我刚刚尝试了您的建议,但它仍然崩溃。事实上,我在调试时已经检查过 newValue 不是 nil,但是不,它具有以下值:Printing description of newValue: (Double?) newValue = 1.2664 谢谢!
【解决方案3】:

所以最后,我联系了 Apple 技术支持。 他们无法重现该问题。

我想也许我不需要保存货币汇率,因为在报价更新期间,该函数将检查它需要的货币汇率,并根据需要重新填充字典。 所以我停用了我创建的用于保存 CurrencyRateStore 并使用 NSKeyedUnarchiver 重新加载它的方法。 显然,崩溃已经消失了!

【讨论】:

  • 对于看到这个的其他人:我通过更改存储目录的名称解决了这个问题 - 突然崩溃消失了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多