使用NSUserDefaults'造成的死锁同步操作GCD队列

时间:2017-03-02 04:08:18

标签: ios swift xcode

上下文

我们有一个事件跟踪模块,可以在触发报告条件时批量报告收集的事件。收集的每个事件都标有唯一的event index。为了确保唯一性,event index代的工作放在同步队列中,该模块将从其他线程调用。

代码段

class EventIndexManager {

fileprivate static let sharedInstance = EventIndexManager()
fileprivate var eventIndexQueue = DispatchQueue(label: "com.johnkui.EventIndex.SyncQueue")
fileprivate var curEventIndex: UInt64 = 0

static func sharedManager() -> EventIndexManager {
    return sharedInstance
}

func getEventIndex() -> UInt64 {
    eventIndexQueue.sync {
        if self.curEventIndex != 0 {
            self.curEventIndex += 1
        } else {
            if let prevEventIndex = UserDefaults.standard.value(forKey: "event_index") as? UInt64 {
                self.curEventIndex = prevEventIndex + 1
            } else {
                self.curEventIndex = 1
            }
        }

        let curEventIndex = self.curEventIndex
        eventIndexQueue.async {
            let eventIndex = self.curEventIndex > curEventIndex ? self.curEventIndex : curEventIndex
            UserDefaults.standard.set(eventIndex, forKey: "event_index")
            UserDefaults.standard.synchronize()
        }
    }

    return self.curEventIndex
}
}

class EventTask: Taskable {
var event: String
var parameters: [String : Any]
var eventIndex: UInt64

init(event: String, parameters: [String : Any]) {
    self.event = event
    self.parameters = parameters
    self.eventIndex = EventIndexManager.sharedManager().getEventIndex()
    super.init()
}
}


DispatchQueue.main.async(execute: { () -> Void in
                let task = EventTask(event: event, parameters: i18nParameters)
                self.tasks.append(task)
            })

堆栈

这是调用堆栈的一部分

calling stack

问题

为什么会造成死锁?我的代码段有什么问题?

1 个答案:

答案 0 :(得分:1)

您的代码中存在循环依赖:

  1. 共享实例的初始化需要EventIndexManager
  2. 的对象
  3. EventIndexManager的init函数需要初始化的共享实例。
  4. 这不起作用,因为变量sharedManager的初始化时间不早于init函数之后。你不应该在init函数中访问sharedManagersharedMananger()