在OC中有dispatch_once來實現,在Swift中我們需要自己來根據其原理來實現,類似于增加一個哨兵來標識是否執行過了
原子操作
對于一個資源,在寫入或讀取時,只允許在一個時刻一個角色進行操作,則為原子操作。Swift中 let 聲明的資源,永遠是原子性的。在我們購買火車票時需要保證票數不會在多個線程中同時進行修改,這時就可以使用這種方式來實現。
- OC實現方式
// 加鎖
@synchronized(<#token#>) {
<#statements#>
}
- Swift實現方式
objc_sync_enter(lock)
// TODO:
objc_sync_exit(lock)
購買火車票
// 在Playeground實現
import UIKit
var ticket = 10000
func buyTicket(userName: String) {
DispatchQueue.global().async {
// objc_sync_enter(ticket)
let count = ticket - 1
ticket = count
// objc_sync_exit(ticket)
print("\(userName)買了一張票,剩余票數\(ticket)")
}
}
for i in 1 ... 200 {
buyTicket(userName: "hc\(i)")
}
結果如下:
hc6買了一張票,剩余票數9999
hc3買了一張票,剩余票數9998
hc1買了一張票,剩余票數9999
hc4買了一張票,剩余票數9998
hc2買了一張票,剩余票數9999
hc7買了一張票,剩余票數9998
hc5買了一張票,剩余票數9998
hc8買了一張票,剩余票數9997
hc9買了一張票,剩余票數9997
hc10買了一張票,剩余票數9997
hc11買了一張票,剩余票數9996
hc12買了一張票,剩余票數9996
hc14買了一張票,剩余票數9995
hc13買了一張票,剩余票數9995
hc15買了一張票,剩余票數9994
hc16買了一張票,剩余票數9994
hc17買了一張票,剩余票數9994
hc19買了一張票,剩余票數9994
hc18買了一張票,剩余票數9994
hc20買了一張票,剩余票數9993
hc22買了一張票,剩余票數9993
hc21買了一張票,剩余票數9993
hc23買了一張票,剩余票數9993
hc24買了一張票,剩余票數9992
hc25買了一張票,剩余票數9992
hc26買了一張票,剩余票數9991
hc27買了一張票,剩余票數9991
hc28買了一張票,剩余票數9991
hc29買了一張票,剩余票數9991
···
將加鎖部分objc_sync_enter(ticket)
,objc_sync_exit(ticket)
打開后結果如下:
hc1買了一張票,剩余票數9999
hc9買了一張票,剩余票數9998
hc12買了一張票,剩余票數9997
hc17買了一張票,剩余票數9996
hc20買了一張票,剩余票數9995
hc21買了一張票,剩余票數9994
hc22買了一張票,剩余票數9993
hc23買了一張票,剩余票數9992
hc24買了一張票,剩余票數9991
hc25買了一張票,剩余票數9990
hc26買了一張票,剩余票數9989
hc27買了一張票,剩余票數9988
hc28買了一張票,剩余票數9987
hc33買了一張票,剩余票數9986
hc38買了一張票,剩余票數9985
hc42買了一張票,剩余票數9984
hc47買了一張票,剩余票數9983
hc51買了一張票,剩余票數9982
hc55買了一張票,剩余票數9981
···
dispatch_once在Swift中的實現
extension DispatchQueue {
fileprivate static var _onceToken = [String]()
static func once(token: String, block: () -> Void) {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
if _onceToken.contains(token) {
return
}
_onceToken.append(token)
block()
}
}