swift 具有参与者的观察者模式

dxpyg8gm  于 2023-02-11  发布在  Swift
关注(0)|答案(1)|浏览(185)

我尝试实现一些可以通知其状态更改的存储库。

protocol Observer {
}

actor Repository: Actor {
    var observers: [Observer] = []
    func add(observer: Observer) {
        self.observers.append(observer)
    }
}

并为其添加单元测试

func test_get_update() async {
    let repository = Repository()
    let observer = MockObserver()    
    await repository.add(observer: observer)
}

并得到警告
在隐式异步调用中传递给执行元隔离示例方法“add(observer:)”的不可发送类型“any Observer”不能跨越执行元边界
但是在主应用程序中没有任何警告。

class Bar {
    func foo() async {
        let repository = Repository()
        let observer = MockObserver()
        
        await repository.add(observer: observer)
    }
}

我不明白这个仓库的实现对不对?

vwkv1x7d

vwkv1x7d1#

当然,您可以将Observer设置为Sendable类型:

protocol Observer: Sendable {
    func observe(something: Int)
}

struct MockObserver: Observer {
    func observe(something: Int) {
        print("I observed \(something)")
    }
}

actor Repository {
    private var observers: [any Observer] = []

    func add(observer: any Observer) {
        observers.append(observer)
    }

    private func notifyObservers(value: Int) {
        for observer in observers {
            observer.observe(something: value)
        }
    }

    func doSomething() {
        notifyObservers(value: 42)
    }
}

let myRepo = Repository()
Task {
    let myObserver = MockObserver()
    await myRepo.add(observer: myObserver)
    await myRepo.doSomething()
}

但是由于Sendable对事物施加了太多的限制,这可能会使实现一个有趣的观察者成为一个挑战。
我倾向于使用合并框架中已有的Observer实现:

actor AnotherRepo {
    nonisolated let interestingState: AnyPublisher<Int, Never>;
    private let actualState = PassthroughSubject<Int, Never>();

    init() {
        interestingState = actualState.eraseToAnyPublisher()
    }

    func doSomething() {
        actualState.send(42)
    }
}

let anotherRepo = AnotherRepo()
anotherRepo.interestingState.sink { print("I also observed \($0)") }

Task {
    await anotherRepo.doSomething()
}

相关问题