Swift 并发:使第 3 方库符合参与者隔离

问题描述 投票:0回答:1

我正在将一些代码库转换为使用 Swift 并发性,但在此过程中遇到了一些障碍。

我正在处理的当前项目有一些它依赖的第三方库,并且在其中一个库中,有一个委托协议,需要从其方法返回一些数据值。

以下是库中委托方法类型的示例:

public protocol FooDelegate: AnyObject {
    func foo() -> CGFloat
}

我正在尝试从协议的实现中返回一些值,如下所示:

extension ViewController: FooDelegate {
    func foo() -> CGFloat { // <- Cannot satisfy requirement from protocol
        view.bounds.height
    }
}

在不做任何修改的情况下,上述与MainActor隐式隔离,无法满足FooDelegate协议的要求。

我尝试过的一个解决方案是用

nonisolated
标记函数实现:

extension ViewController: FooDelegate {
    nonisolated func foo() -> CGFloat {
        view.bounds.height // <- Cannot be referenced from a non-isolated context
    }
}

但这不起作用,因为它引用了视图控制器的视图。这会导致从非隔离同步上下文引用

view
。 (这还存在一些其他问题,因为传递到任何委托函数的任何值都需要符合
Sendable
才能在参与者之间传递
)。

我的问题是,有没有办法采用第 3 方库并以某种方式扩展它,以便它符合正确的参与者隔离,而无需修改其源代码?

ios swift concurrency actor swift-concurrency
1个回答
0
投票

使用

MainActor.assumeIsolated {}

extension ViewController: FooDelegate {
    nonisolated func foo() -> CGFloat {
        MainActor.assumeIsolated {
            view.bounds.height
        }
    }
}

来自文档:

/// A safe way to synchronously assume that the current execution context belongs to the MainActor.
///
/// This API should only be used as last resort, when it is not possible to express the current
/// execution context definitely belongs to the main actor in other ways. E.g. one may need to use
/// this in a delegate style API, where a synchronous method is guaranteed to be called by the
/// main actor, however it is not possible to annotate this legacy API with `@MainActor`.

可用:macOS 14.0、iOS 17.0、watchOS 10.0、tvOS 17.0

© www.soinside.com 2019 - 2024. All rights reserved.