关于Swift中的同步范围

时间:2016-07-02 19:11:03

标签: objective-c swift

目标-C:

@synchronized {
    return;
}
NSLog(@"This line of code does not run.");
  

Objective-C的@synchronized是一个语言级指令,并没有引入新的函数作用域。

夫特:

synchronized {
    return
}
print("This line of code does run.")


func synchronized(lock: AnyObject, @noescape closure: () -> Void) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}
  

Synchronized使用闭包,它引入了一个函数范围。

问题:

我可以在Swift中做同样的事吗?不引入新的功能范围。

真实问题

public func stopRecording() {

    synchronized(self) {
        guard status == .Recording else { return }
        status = .StoppingRecording
    }

    // Many somethings need to do, and I don`t want to write into the closure.
    finishRecording()
    ......
    ......
    ......
}

解决方法:

if (synchronized(self) { return true }) {
    return
}

print(@"This line of code does not run.")


func synchronized(lock: AnyObject, @noescape closure: () -> Bool) -> Bool {
    objc_sync_enter(lock)
    defer {
        objc_sync_exit(lock)
    }
    return closure()
}

有人有一个优雅的解决方案吗?

1 个答案:

答案 0 :(得分:2)

我只是提出了一个并不太糟糕的解决方案。我们不能引入不会引入新范围的自定义语言构造,因此我们需要使用现有的一种。 if语句应该适用于此。我为此做了一个小类,它只做了一件事:锁定给定的对象并检查unlock方法在解除分配之前是否被调用(以及一些用于调试的新增内容):

final class LockingManager {
    let obj: AnyObject

    let file: StaticString
    let line: UInt

    var locked = true

    init(obj: AnyObject, file: StaticString, line: UInt) {
        self.obj = obj
        self.file = file
        self.line = line
        objc_sync_enter(obj)
    }

    func unlock() {
        objc_sync_exit(obj)
        locked = false
    }

    deinit {
        precondition(!locked, "Object \(obj) not unlocked", file: file, line: line)
    }
}

使用这样的函数:

func lock(obj: AnyObject, file: StaticString = #file, line: UInt = #line) -> (() -> Void)? {
    return LockingManager(obj: obj, file: file, line: line).unlock
}

我们可以像这样使用它:

if let unlock = lock(obj: self) {
    defer { unlock() }
    // Do stuff
}

由于方法永远不会返回nil,因此您不需要else部分。由于解锁方法只保留LockingManager的唯一引用,因此只有在if语句中LockingManager被取消分配后才能使用。取消分配后,它会检查是否调用了unlock方法,如果没有,则会抛出错误。

我知道这不是一个非常好的解决方案,但它确实有效,因为它没有引入新的范围(并且另外检查正确的用法)。

另一个解决方案是使用简单的函数调用和do块:

do {
    objc_sync_enter(self)
    defer { objc_sync_exit(self) }

    // Do stuff
}

我个人更喜欢第二种方法(有一些更好的命名功能),因为它更清楚它的作用。