目标-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()
}
有人有一个优雅的解决方案吗?
答案 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
}
我个人更喜欢第二种方法(有一些更好的命名功能),因为它更清楚它的作用。