iOS15之Swift5.5 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)
    }

如果在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
            }
        }
    }

旧的写法可能是:

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
            }
        }
    }

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

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
    }

//方式2

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

然后使用一般是这样:


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

旧方式之一:

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
        }
    }

其他语法

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

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
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值