在 Swift 5 协议中使用 @objc

问题描述

我在 swift 协议中使用 @objc 代码时遇到问题,想知道是否有解决方法

目前,我有代码

import UIKit

@objc
protocol TrackScreenshot {
    func registerObserver()
    func removeObservers()
}

extension TrackScreenshot where Self: ScreenTracking {
    func registerObserver() {
        NotificationCenter.default.addobserver(self,selector: #selector(trackScreenshot),name: UIApplication.userDidTakeScreenshotNotification,object: nil)
    }
    
    func removeObservers() {
        NotificationCenter.default.removeObserver(self,object: nil )
    }
    
    func trackScreenshot() {
        print(screenName.rawValue)
    }
}

所以我想继承 TrackScreenshot 协议并使屏幕易于跟踪。 但是一个问题。 #selecor 上的 registerObserver() 方法要求将 @objc 添加到 trackScreenshot 方法,但如果我这样做,Xcode 会在 trackScreenshot() 行上抱怨并告诉:@objc 只能与类、@objc 协议和具体扩展的成员一起使用班级

有没有办法解决这个问题? 也试过了:

    NotificationCenter.default.addobserver(forName: UIApplication.userDidTakeScreenshotNotification,object: nil,queue: nil) { _ in
        print(self.screenName.rawValue)
    }

但它不起作用,并且观察者无法移除并留在圆圈中,因此在打开新屏幕时打印所有以前的屏幕名称

欢迎提供任何帮助!提前致谢!

解决方法

您也可以使用委托来跟踪屏幕截图通知,您可以根据需要随意重构:

public protocol ScreenshotDelegate: AnyObject {
    func screenshotDetected()
}

open class ScreenshotTracker: NSObject {
    
    private weak var delegate: ScreenshotDelegate?
    
    public init(delegate: ScreenshotDelegate) {
        self.delegate = delegate
       
        NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification,object: nil,queue: OperationQueue.main) { notification in
            delegate.screenshotDetected()
            print("Screenshot notification")
        }
    }
}

视图控制器设置:

override func viewDidLoad() {
    super.viewDidLoad()
    let _ = ScreenshotTracker(delegate: self)
}

extension ViewController: ScreenshotDelegate {
    func screenshotDetected() {
        print("screenshot taken!!!")
    }
}
,

我会使用通知观察的闭包形式而不是选择器/方法:

protocol TrackScreenshot {
    func registerObserver(handler: (()->Void)?)
    func removeObservers()
}

extension TrackScreenshot where Self: ScreenTracking {
    func registerObserver(handler: (()->Void)?) {
        NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification,queue: nil) { (notification) in
            handler?()
        }
    }
    
    func removeObservers() {
        NotificationCenter.default.removeObserver(self,name: UIApplication.userDidTakeScreenshotNotification,object: nil )
    }
}

那么你的用法是这样的:

self.registerObserver { [weak self] in
    guard let self = self else {
        return
    }
    print("Screen shot")'
}