在ObjC协议上的协议扩展
我有一个Objective-C协议,主要用于Objective-C对象和一个或两个Swift对象。
我想在Swift中扩展协议并添加2个函数。 一个注册通知,另一个处理通知。
如果我添加这些
func registerForPresetLoadedNotification() {
NSNotificationCenter.defaultCenter().addObserver(self as AnyObject,
selector: #selector(presetLoaded(_:)),
name: kPresetLoadedNotificationName,
object: nil)
}
func presetLoaded(notification: NSNotification) {
}
我在#selector上发现一个错误,它表示Argument of '#selector' refers to a method that is not exposed to Objective-C
如果我将presetLoaded标记为@objc, @objc
一个错误,指出@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
我也不能将协议扩展标记为@objc
当我创建Objective-C协议作为Swift协议时,我得到相同的错误。
有没有一种方法可以实现这个功能,可以用于使用该协议的Objective-C和Swift类?
事实上,你不能真正将协议扩展的功能标记为@objc (或者动态的 ,这是相当于这种方式的)。 Objective-C运行时只允许调用类的方法。
在你的特定情况下,如果你真的想通过协议扩展来实现,我可以提出以下解决方案(假设你的原始协议被命名为ObjcProtocol )。
我们为通知处理程序创建一个包装:
final class InternalNotificationHandler {
private let source: ObjcProtocol
init(source: ObjcProtocol) {
// We require source object in case we need access some properties etc.
self.source = source
}
@objc func presetLoaded(notification: NSNotification) {
// Your notification logic here
}
}
现在我们需要扩展ObjcProtocol来引入所需的逻辑
import Foundation
import ObjectiveC
internal var NotificationAssociatedObjectHandle: UInt8 = 0
extension ObjcProtocol {
// This stored variable represent a "singleton" concept
// But since protocol extension can only have stored properties we save it via Objective-C runtime
private var notificationHandler: InternalNotificationHandler {
// Try to an get associated instance of our handler
guard let associatedObj = objc_getAssociatedObject(self, &NotificationAssociatedObjectHandle)
as? InternalNotificationHandler else {
// If we do not have any associated create and store it
let newAssociatedObj = InternalNotificationHandler(source: self)
objc_setAssociatedObject(self,
&NotificationAssociatedObjectHandle,
newAssociatedObj,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return newAssociatedObj
}
return associatedObj
}
func registerForPresetLoadedNotification() {
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(notificationHandler.presetLoaded(_:)),
name: kPresetLoadedNotificationName,
object: self)
}
func unregisterForPresetLoadedNotification() {
// Clear notification observer and associated objects
NSNotificationCenter.defaultCenter().removeObserver(self,
name: kPresetLoadedNotificationName,
object: self)
objc_removeAssociatedObjects(self)
}
}
我知道这看起来可能不那么优雅,所以我真的会考虑改变核心方法。
一个注意:你可能想限制你的协议扩展
extension ObjcProtocol where Self: SomeProtocolOrClass
我找到了一种方法:)只要避免@objc在一起:D
//Adjusts UITableView content height when keyboard show/hide
public protocol KeyboardObservable {
func registerForKeyboardEvents()
func unregisterForKeyboardEvents()
}
extension KeyboardObservable where Self: UITableView {
public func registerForKeyboardEvents() {
NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil) { notification in
self.keyboardDidShow(notification)
}
NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil) { notification in
self.keyboardWillHide(notification)
}
}
private func keyboardDidShow(_ notification: Notification) {
let rect = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let height = rect.height
var insets = UIEdgeInsetsMake(0, 0, height, 0)
insets.top = contentInset.top
contentInset = insets
scrollIndicatorInsets = insets
}
private func keyboardWillHide(_ notification: Notification) {
var insets = UIEdgeInsetsMake(0, 0, 0, 0)
insets.top = contentInset.top
UIView.animate(withDuration: 0.3) {
self.contentInset = insets
self.scrollIndicatorInsets = insets
}
}
public func unregisterForKeyboardEvents() {
NotificationCenter.default.removeObserver(self)
}
}
例
class CreateStudentTableView: UITableView, KeyboardObservable {
init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
registerForKeyboardEvents()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
unregisterForKeyboardEvents()
}
}
链接地址: http://www.djcxy.com/p/35745.html
上一篇: Protocol extension on an ObjC protocol
下一篇: Getting sequential logs while executing tests in parallel