Swift并发:使第三方库符合角色隔离

1u4esq0p  于 4个月前  发布在  Swift
关注(0)|答案(1)|浏览(53)

我正在将一些代码库转换为使用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才能在参与者之间传递 *)。
我的问题是,有没有一种方法可以使用第三方库并以某种方式对其进行扩展,使其符合适当的参与者隔离,而不必修改其源代码?

vof42yt1

vof42yt11#

使用MainActor.assumeIsolated {}

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

字符串
从docs:

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

相关问题