在 Swift 5 个协议中使用 @objc
Using @objc in Swift 5 protocols
我在 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, name: UIApplication.userDidTakeScreenshotNotification, 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")
}
}
}
ViewController 设置:
override func viewDidLoad() {
super.viewDidLoad()
let _ = ScreenshotTracker(delegate: self)
}
extension ViewController: ScreenshotDelegate {
func screenshotDetected() {
print("screenshot taken!!!")
}
}
我会使用通知观察的闭包形式而不是 selector/method:
protocol TrackScreenshot {
func registerObserver(handler: (()->Void)?)
func removeObservers()
}
extension TrackScreenshot where Self: ScreenTracking {
func registerObserver(handler: (()->Void)?) {
NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, 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")'
}
我在 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, name: UIApplication.userDidTakeScreenshotNotification, 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")
}
}
}
ViewController 设置:
override func viewDidLoad() {
super.viewDidLoad()
let _ = ScreenshotTracker(delegate: self)
}
extension ViewController: ScreenshotDelegate {
func screenshotDetected() {
print("screenshot taken!!!")
}
}
我会使用通知观察的闭包形式而不是 selector/method:
protocol TrackScreenshot {
func registerObserver(handler: (()->Void)?)
func removeObservers()
}
extension TrackScreenshot where Self: ScreenTracking {
func registerObserver(handler: (()->Void)?) {
NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, 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")'
}