文章

swift函数回调改写为swift协程concurrency的async函数

之前也写过一篇swift的新特性文章,但是app最低版本没到iOS13.0,所以一直没有用到业务代码中。

理论性知识相关就不写了,这里直接上代码改造

异步串行改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 两个异步方法
func helloAsync(onComplete: @escaping (Int) -> Void) {
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        onComplete(Int(arc4random()))
    }
}

func hiAsync(onComplete: @escaping (Int) -> Void) {
    DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
        onComplete(Int(arc4random()))
    }
}

// 两个异步变串行,例如请求完一个接口拿到结果在请求另一个接口

func concurrency() {
    helloAsync { [weak self] result1 in
        self?.hiAsync { result2 in
            print("1. \(result1)-\(result2)")
        }
    }
}

改之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 两个方法修改
func helloAsync() async -> Int {
    await withCheckedContinuation { continuation in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            let result = Int(arc4random())
            print("a. \(result)")
            continuation.resume(returning: result)
        }
    }
}
func hiAsync() async -> Int {
    await withCheckedContinuation { continuation in
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            let result = Int(arc4random())
            print("b. \(result)")
            continuation.resume(returning: result)
        }
    }
}

var result_g = -1
func concurrency() {
    Task { // 必须要用task包裹,不然就只能在async方法中调用
        let result = await helloAsync()
        print("1. \(result)")
        let result2 = await hiAsync()
        print("2. \(result2)")

        result_g = result // 不会报错
    }
}

异步DispatchGroup改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func concurrency() {
    // 两个异步都执行完再响应
    var r1 = -1
    var r2 = -1
    let group = DispatchGroup()
    group.enter()
    helloAsync { result1 in
        r1 = result1
        group.leave()
    }
    group.enter()
    hiAsync { result2 in
        r2 = result2
        group.leave()
    }

    group.notify(queue: .main) {
        print("2. \(r1)-\(r2)")
    }
}

改造后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
var r1 = -1
var r2 = -1

func concurrency() {
    Task {
        await processAsync2()
    }
}

// 写法1,将hello和hi都改成2秒延迟
// print在两秒之后同时输出,说明hi没有等待hello执行完
func processAsync1() async {
    async let loadHello = helloAsync()
    async let loadHi = hiAsync()

    let hello = await loadHello
    r1 = hello // 可以这么写
    print("Done: \(hello)")
    let hi = await loadHi
    r2 = hi
    print("Done: \(hi)")
}
// 写法2
func update1(_ r: Int) {
    r1 = r
}

func update2(_ r: Int) {
    r2 = r
}

func processAsync2() async {
  	// 模拟两个接口,处理两个接口返回的值不一样的情况
    let value = await withTaskGroup(of: Any.self, returning: Any.self) { group in
        group.addTask {
            let r = await self.helloAsync()
            // self.r1 = r 不能这么写,必须抽出一个方法
            await self.update1(r)
            return r
        }
        group.addTask {
            let r = await self.hiAsync()
            await self.update2(r)
            return r
        }
        guard let first = await group.next() else {
            group.cancelAll()
            return 0
        }
        let second = await group.next() ?? 0
        group.cancelAll()
        return (first, second)

//            var result: [Any] = []
//            for await value in group {
//                result.append(value)
//            }
//            return result
    }
    if let value_ = value as? (Int, Int) {
        print("Done: \(r1) + \(r2) = \(value_.0 + value_.1)")
    }
}

相比来看,第一种写法比较简单

参考文档

https://www.bennyhuo.com/2021/10/13/swift-coroutines-02-wrap-callback/

https://www.cnswift.org/concurrency

https://onevcat.com/2021/07/swift-concurrency/

https://juejin.cn/post/7181121378471378981

https://juejin.cn/post/7169914508360548360

https://stackoverflow.com/questions/78496014/main-actor-isolated-static-property-text-cannot-be-mutated-from-a-non-isolated

本文由作者按照 CC BY 4.0 进行授权