我很難解釋這個問題,所以我會盡力而為。
我有這段代碼:
protocol MyListener
{
func setupMyViewControllers() //code I would like to share with any UIViewController that conforms to this protocol
func receiveUpdateA() //each protocol-conforming class should have its own implementation
func receiveUpdateB() //each protocol-conforming class should have its own implementation
}
//my classes hierarchy
class A: UIViewController {}
class B: UIViewController {}
class b: B {}
因此,與其撰寫像下面這樣的重復代碼:
extension A: MyListener
{
func setupMyViewControllers()
{
NotificationCenter.default.addObserver(self, selector: #selector(receiveUpdateA(_:)), name: "receiveUpdateA", object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(receiveUpdateB(_:)), name: "receiveUpdateB", object: nil)
}
//rest of protocol implementations
func receiveUpdateA() {/*...*/}
func receiveUpdateB() {/*...*/}
}
extension B: MyListener
{
func setupMyViewControllers()
{
NotificationCenter.default.addObserver(self, selector: #selector(receiveUpdateA(_:)), name: "receiveUpdateA", object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(receiveUpdateB(_:)), name: "receiveUpdateB", object: nil)
}
//rest of protocol implementations
func receiveUpdateA() {/*...*/}
func receiveUpdateB() {/*...*/}
}
我嘗試了以下(沒有成功):
extension MyListener where Self: UIViewController
{
func setupMyViewControllers()
{
NotificationCenter.default.addObserver(self, selector: #selector(receiveUpdateA(_:)), name: "receiveUpdateA", object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(receiveUpdateB(_:)), name: "receiveUpdateB", object: nil)
}
}
extension A: MyListener
{
//rest of protocol implementations
func receiveUpdateA() {/*...*/}
func receiveUpdateB() {/*...*/}
}
extension B: MyListener
{
//rest of protocol implementations
func receiveUpdateA() {/*...*/}
func receiveUpdateB() {/*...*/}
}
我認為這樣我可以共享設定代碼,但仍然能夠在單獨的擴展中擴展剩余的“receiveUpdate”功能。但是我陷入了一個錯誤回圈。我收到“無法將‘receiveUpdateA’用作選擇器,因為協議‘MyListener’未公開給 Objective-C。但是,將其公開給 obj-c 然后給我一個錯誤,即協議擴展不能具有 obj-c 函式。
有沒有辦法在不擴展整個UIViewControllerto的情況下實作這一目標MyListener?(我什至不確定這是否可行。似乎核心問題是使用Selectors)
uj5u.com熱心網友回復:
不知道您現在使用的是什么 Swift/XCode 版本,但以下內容似乎適用于 Swift 5.7.1。
@objc protocol MyListener {
func receiveUpdateA()
func receiveUpdateB()
}
extension MyListener {
func setupMyViewControllers() {
NotificationCenter.default.addObserver(
self,
selector: #selector(receiveUpdateA),
name: NSNotification.Name("receiveUpdateA"),
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(receiveUpdateB),
name: NSNotification.Name("receiveUpdateB"),
object: nil
)
}
}
//my classes hierarchy
class A: UIViewController {}
class B: UIViewController {}
extension A: MyListener {
//rest of protocol implementations
@objc func receiveUpdateA() {/*...*/}
@objc func receiveUpdateB() {/*...*/}
}
extension B: MyListener {
//rest of protocol implementations
@objc func receiveUpdateA() {/*...*/}
@objc func receiveUpdateB() {/*...*/}
}
盡管我會說你不應該將 DRY 視為宗教規則,但這里有一個使用 Apple 自己的 Rx 等價物的替代實作:
import UIKit
import Combine
protocol ObservesNotificiationCenter {
}
extension ObservesNotificiationCenter {
func onNotification(withName name: String) -> AnyPublisher<Notification, Never> {
return NotificationCenter.default.publisher(
for: NSNotification.Name(name)
).eraseToAnyPublisher()
}
}
@objc protocol ReceivesUpdates {
func receiveUpdateA(notificiation: Notification)
func receiveUpdateB(notificiation: Notification)
}
extension ReceivesUpdates where Self: ObservesNotificiationCenter {
func setupNotifications() -> Set<AnyCancellable> {
var cancellables: Set<AnyCancellable> = []
onNotification(withName: "receiveUpdateA")
.receive(on: DispatchQueue.main)
.sink(receiveValue: receiveUpdateA(notificiation:))
.store(in: &cancellables)
onNotification(withName: "receiveUpdateB")
.receive(on: DispatchQueue.main)
.sink(receiveValue: receiveUpdateB(notificiation:))
.store(in: &cancellables)
return cancellables
}
}
class ViewController: UIViewController, ObservesNotificiationCenter, ReceivesUpdates {
private var cancellables: Set<AnyCancellable>!
override func viewDidLoad() {
super.viewDidLoad()
cancellables = setupNotifications()
}
func receiveUpdateA(notificiation: Notification) {
}
func receiveUpdateB(notificiation: Notification) {
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/537855.html
