信号量:一个计数信号,可用来资源访问的并发控制
DispatchSemaphore(value: 1)// 初始化信号量
semaphore.wait() //等待信号,信号量-1,当信号总量为0时会一直等待
semaphore.signal() //发送信号,信号量+1
例如点击一次,连续执行4次动画,控制前面的动画执行完成后才会执行后面的动画。
效果为:
1644652552241107.gif
ViewController.swift
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for i in 0..<4 {
carAnimation(index: i)
}
}
func carAnimation(index: Int){
var type = DirectionType.top
switch index {
case 0:
type = .top
case 1:
type = .bottom
case 2:
type = .left
default:
type = .right
}
AnimateManager.shareInstance.showAlertBanner(view: self.view, dirtype: type)
}
AnimateManager.swift中处理信号量执行过程
class AnimateManager: NSObject {
let semaphore = DispatchSemaphore(value: 1) //初始化信号量为1
static let shareInstance: AnimateManager = {
let instance = AnimateManager()
return instance
}()
private override init() {}
lazy var ferrariv: FerrariView = {
let ferr = FerrariView()
return ferr
}()
func showAlertBanner(view: UIView, dirtype: DirectionType) {
let curQueue = DispatchQueue(label: "curQueue")
curQueue.async {
self.semaphore.wait() //信号量-1
DispatchQueue.main.async {
self.refreshUI(view: view, dirtype:dirtype)
}
}
}
func refreshUI(view: UIView, dirtype: DirectionType) {
view.addSubview(ferrariv)
ferrariv.frame = view.bounds
weak var weakself = self
/*
开始执行动画
ferrariv可自行封装想要的动画效果
*/
ferrariv.startAnimateWithDirection(direction: dirtype) {
//动画执行完成时的回调
weakself?.ferrariv.removeFromSuperview()
weakself?.semaphore.signal() //信号量+1
}
}
}
FerrariView.swift
enum DirectionType : Int{
case top = 0,bottom,left,right
}
class FerrariView: UIView {
var ferrarisImagesOne = [UIImage]()
var ferrarisImagesTwo = [UIImage]()
var ferrarisImagesThree = [UIImage]()
var ferrarisImagesFour = [UIImage]()
var publicw = 300.0
var bgImgView: UIImageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
ferrarisImagesOne = loadImgsArr(count: 6, prefix: "ferraris")
ferrarisImagesTwo = loadImgsArr(count: 6, prefix: "ferrarisRight")
ferrarisImagesThree = loadImgsArr(count: 6, prefix: "ferrarisBack")
ferrarisImagesFour = loadImgsArr(count: 6, prefix: "ferrarisLeft")
addSubview(bgImgView)
}
func startAnimateWithDirection(direction:DirectionType,complete:@escaping()->()){
switch direction {
case .top:
bgImgView.animationImages = ferrarisImagesOne
startDriveAnimat(x: -publicw, y: 40*screenH/568.0, movex: (screenW*0.5+publicw*0.5), movey: 100*screenH/568.0, complete: {
complete()
})
case .bottom:
bgImgView.animationImages = ferrarisImagesTwo
startDriveAnimat(x: -publicw, y: (200*screenH/568.0-publicw*0.5+40*screenH/568.0), movex: (screenW*0.5+publicw*0.5), movey: -100*screenH/568.0, complete: {
complete()
})
case .left:
bgImgView.animationImages = ferrarisImagesThree
startDriveAnimat(x: publicw, y: (200*screenH/568.0-publicw*0.5+40*screenH/568.0), movex:-(screenW*0.5+publicw*0.5 - 75*screenH/568.0), movey: -100*screenH/568.0, complete: {
complete()
})
default:
bgImgView.animationImages = ferrarisImagesFour
startDriveAnimat(x: publicw, y: -40*screenH/568.0, movex: -(screenW*0.5+publicw*0.5 - 75*screenH/568.0), movey: 100*screenH/568.0, complete: {
complete()
})
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loadImgsArr(count: Int, prefix: String) -> [UIImage] {
var imgs = [UIImage]()
for i in 0..<count {
let imgName: String = prefix+String(i+1)
if let img = UIImage.init(named: imgName) {
imgs.append(img)
}
}
return imgs
}
func startDriveAnimat(x:CGFloat,y:CGFloat,movex:CGFloat,movey:CGFloat,complete:@escaping()->()) {
bgImgView.animationDuration = 1.0
bgImgView.startAnimating()
bgImgView.frame = CGRect(x: x, y: y, width: publicw, height: publicw)
bgImgView.moveXY()(movex,movey)?.animate()(2.0)
//从一个点开到另一个点
weak var weakself = self
bgImgView.animationCompletion = {
weakself?.bgImgView.moveXY()(0,0)?.animate()(1.0)
weakself?.bgImgView.animationCompletion = {
weakself?.bgImgView.moveXY()(movex,movey)?.makeScale()(0.01)?.animate()(2.0)?.animationCompletion = {
complete()
}
}
}
}
}