当前位置:   article > 正文

iOS15之Swift5.5 Concurrency 并发编程初探_swift concurrency

swift concurrency

iOS15之Swift5.5 Concurrency 并发编程初探

前言

在Swift5.5以前或Object-C时代iOS开发要实现并发代码,一般要自己使用多线程,如DispatchGroup,DispatchSemaphore等等,且都是命令式代码,并不能使用诸如await等响应式代码的方式,异步转同步直观的获取异步资源。Swift5.5 Concurrency就解决了这个问题,我认为这是一个非常棒的设计,虽然其他语言老早就有类似的语法,但不得不再赞一次。但是令人遗憾的是,Swift5.5 Concurrency编程是建立在Xcode13以及iOS15之上的,也就是说旧项目的支持依然无法使用。以下是介绍Swift5.5 Concurrency的写法,我也会使用旧有的线程方式作为对比。

参考文献

Swift5.5 Concurrency

demo code

基本语法

这里我以下载网络图为例子。

首先要说的是 await 必须与 async 搭配使用

func downloadImage(url: String) async -> UIImage? {
        return await loadImage(url: url)
    }
  • 1
  • 2
  • 3

如果在viewDidLoad 等不能 async的场景怎么办?(无需纠结为什么不行,直接编译会报错,个人理解是Concurrency也是多线程的方式实现,viewDidLoad等方法直接操作的UI必然在主线程,肯定是不能async的)

那就要用Task包裹,如在viewDidLoad获取一张网络图并显示。

使用await可以这么写

override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.imageView)
        Task {
            let image = await self.loadImage()
            DispatchQueue.main.async {
                self.imageView.image = image
            }
        }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

旧的写法可能是:

override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.imageView)
        self.asyncLoadImage(url: "http://image.jerryfans.com/iterm2_bg_image.jpg") { [weak self] image in
            guard let self = self else { return }
            guard let img = image else { return }
            DispatchQueue.main.async {
                self.imageView.image = img
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

当我们想下载多张网图,且等全部图片下载完再做事情是这样的:

Concurrency方式:

//方式1

func multiImageLoad() async -> [UIImage]? {
        var results: [UIImage] = []
        await withTaskGroup(of: UIImage.self) { taskGroup  in
            for ele in origins.enumerated() {
                taskGroup.addTask {
                    return await self.loadImage(url: origins[ele.offset])!
                }
            }
            for await result in taskGroup {
                results.append(result)
            }
        }
        return results
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

//方式2

func multiImageLoad() async -> [UIImage]? {
        var results: [UIImage] = []
        for ele in origins.enumerated() {
            results.append(await self.loadImage(url: origins[ele.offset])!)
        }
        return results
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后使用一般是这样:


Task {
            guard let images = await multiImageLoad() else { return }
            DispatchQueue.main.async {
                print(images)
                //do your things
            }
        }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

旧方式之一:

func multiImageLoad_old() {
        let group = DispatchGroup()
        group.enter()
        // load img 1
        DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
            group.leave()
        }
        
        group.enter()
        // load img 2
        DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
            group.leave()
        }
        
        group.notify(queue: .main) {
            //do your things
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

其他语法

如等待两三个接口完成,再下一个接口

func multiWaitFinishLoad() async -> [UIImage]? {
        var results: [UIImage] = []
        await withTaskGroup(of: UIImage.self) { taskGroup  in
            for ele in origins.enumerated() {
                taskGroup.addTask {
                    print("begin ele \(ele.offset)")
                    return await self.loadImage(url: origins[ele.offset])!
                }
            }
            for await result in taskGroup {
                results.append(result)
            }
            //等待上面执行完,再做下面的事情
            await taskGroup.waitForAll()
            //取消全部
            // taskGroup.cancelAll()
            print("wait finished and do")
            results.append(await loadImage()!)
        }
        return results
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/460746
推荐阅读
相关标签
  

闽ICP备14008679号