Swift 3.0之后实现Dispatch once扩展

综合技术 简书 (源链)

在Swift 3.0中原有的Dispatch once已经被废弃了,这种写法已经不再被支持了

var token: dispatch_once_t = 0
func test() {
    dispatch_once(&token) {
    }
}

文档说明:

Dispatch

The free function dispatch_once is no longer available in Swift. In Swift, you can use lazily initialized globals or static properties and get the same thread-safety and called-once guarantees as dispatch_once provided. Example:

let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal  // using myGlobal will invoke the initialization code only the first time it is used

官方说我们可以使用懒加载初始化的全局变量或静态属性,也可以得到类似 dispatch_once 提供的线程安全的实现方案,但是有些时候使用这种方式意义不大。

我们可以通过给DispatchQueue实现一个扩展方法来实现原有的功能:

public extension DispatchQueue {

    private static var _onceTracker = [String]()

    /**
     Executes a block of code, associated with a unique token, only once.  The code is thread safe and will
     only execute the code once even in the presence of multithreaded calls.

     - parameter token: A unique reverse DNS style name such as com.vectorform. or a GUID
     - parameter block: Block to execute once
     */
    public class func once(token: String, block:@noescape(Void)->Void) {
        objc_sync_enter(self); defer { objc_sync_exit(self) }

        if _onceTracker.contains(token) {
            return
        }

        _onceTracker.append(token)
        block()
    }
}

通过使用 token 作为唯一标识 执行 once 方法时通过加锁避免多线程下的 token 值不确定的情况。像这样调用:

DispatchQueue.once(token: "com.me.project") {
    print( "Do This Once!" )
}

或者使用UUID

private let _onceToken = NSUUID().uuidString

DispatchQueue.once(token: _onceToken) {
    print( "Do This Once!" )
}

当然如果觉得每次使用 once 方法都要想一个不同的 token 有些伤脑可以使用下面的方式:

public extension DispatchQueue {
    private static var _onceTracker = [String]()

    public class func once(file: String = #file, function: String = #function, line: Int = #line, block:(Void)->Void) {
        let token = file + ":" + function + ":" + String(line)
        once(token: token, block: block)
    }

    /**
     Executes a block of code, associated with a unique token, only once.  The code is thread safe and will
     only execute the code once even in the presence of multithreaded calls.

     - parameter token: A unique reverse DNS style name such as com.vectorform. or a GUID
     - parameter block: Block to execute once
     */
    public class func once(token: String, block:(Void)->Void) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }


        if _onceTracker.contains(token) {
            return
        }

        _onceTracker.append(token)
        block()
    }
}

调用方式更简单:

DispatchQueue.once {
    setupUI()
}

也支持自定义 token 的使用方式:

DispatchQueue.once(token: "com.me.project") {
    setupUI()
}

每次自动生成一个类似 "/Users/iOS/Demo/ViewController.swift:viewWillAppear:136"
这样的 token 避免每次都要费尽脑汁定义一个 token,看起来也更直观。

注意:如果在两个模块中有同名的文件并且使用 once 之处在同一个方法的相同行处,可能会发生冲突。这种情况虽然概率很低但也是有可能发生的,若出现此情况请定义唯一的 token,使用传递参数这种方式来实现。

相关链接

您可能感兴趣的

Capturing Values in Swift Closures In this article, we’ll see two things: how a closure captures a variable, and a specific scenario where the closure captures the self context. ...
Using child view controllers as plugins in Swift A very common problem when building apps for Apple's platforms is where to put common functionality that is used by many different view controllers. ...
23 Swift 注释 单行注释 Swift 中的注释与C 语言的注释非常相似。 单行注释以双正斜杠(//)作为起始标记 // 注释内容 多行注释 其起始标记为单个正斜杠后跟随一个星号(/*) 终止标记为一个星号后跟随单个正斜杠(*/) /* 这是一个, ...
开始用Swift写写小应用 前言: 自去年12月期间就断断续续的把 Swift 的语法部分看完了,但是后面今年上半年杂事太多,没把 Swift 的学习继续下去,这段时间终于有时间了,开始继续 Swift 的学习了。学习编程语言,一定要亲自手敲代码,不能只是理解语法,很多知识点亲自写着体验过后才会刻在脑海里。也有很多...
一看Swift官方文档(一) 上次在群里问了个 self ` = self ` 的语法,有人说这个文档里就有,瞬间觉得应该好好从文档开始学起,于是就有了这个系列。一看先过一遍文档记录笔记,二看将文档里比较常用和重要的特性具体讲解,不确定是否有三看这个东西了。(慢慢填坑) 基础部分 类型标注可以在...
简书责编内容来自:简书 (源链) | 更多关于

阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » Swift 3.0之后实现Dispatch once扩展



专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录