我正试图通过对Objective-C类的快速扩展来符合该类上的Objective-C委托方法。问题是,在下面的swift扩展中定义此函数的主体时,我没有自动完成选项。我不得不从Objective-C手动翻译它,但它仍然不起作用。。我知道委托的设置是正确的,因为当我直接在ObjectiveCConformingClass中提供委托函数体时,它工作得很好(当我编写函数时会自动完成(。
我有一个像这样的快速类(我想我需要解决的问题(:
extension ObjectiveCConformingClass {
func delegateFunction(with index: Int, viewName: String, action: String, dictionary: [String : Any]) {
//Never gets called.
}
}
扩展这样的类:
符合委托的类:
@interface ObjectiveCConformingClass : SuperClass <ObjectiveCDelegate>
//Whatever
@end
代表:
@protocol ObjectiveCDelegate <NSObject>
@optional
- (void)delegateFunction:(NSInteger)index
view:(nonnull NSString *)view
action:(nonnull NSString *)action
dictionary:(nonnull NSDictionary<NSString *, id> *)dictionary;
@end
总结一下:我需要在类的快速扩展中遵循这个委托,而不是实际的类。如果我直接在objective-C类中这样做,效果会很好。有什么想法为什么它不起作用吗?或者这是否可能?
以下是一些相当相似的问题,它们要求不同的东西,所以对我没有帮助。(即这是而不是重复的线程(
- 在Swift中实现ObjectiveC委托
- Objective-C协议的Swift扩展
- 在swift中使用objective-c编写的委托方法
- 在Swift中使用扩展实现委托函数
阅读时请慢慢来
将代表视为id<ProtocolName>
"指向另一个对象的指针">符合协议。
@protocol ObjectiveCDelegate <NSObject>
@optional
- (void)delegateMethod:(NSInteger)index
view:(nonnull NSString *)view
action:(nonnull NSString *)action
dictionary:(nonnull NSDictionary<NSString *, id> *)dictionary;
@end
通常,想要使用委托的@interface ClassName : NSObject
应该有一个属性来保留它或将其设置为nil
(可为null(,这意味着为什么您希望它弱。
@property (nonatomic, weak) id<ObjectiveCDelegate> delegate;
而将成为您的委托的类(对象(必须符合此协议,因此您必须像以前一样在其接口中声明此协议。美得像。。
@interface ObjectiveCConformingClass : SuperClass <ObjectiveCDelegate>
@property (nonatomic, weak) id<ObjectiveCDelegate> delegate;
-(void)invokeDelegate; //for testing.
@end
因为上面的协议有可选的方法声明,所以当你没有实现它时,它不会抛出警告。为了避免在使用ClassName
(对象(的类中处理委托时遇到问题,你需要检查委托属性是否不是nil
,并且是否可以响应所需的方法名。
@implementation ObjectiveCConformingClass
-(void)delegateMethod:(NSInteger)index view:(NSString *)view action:(NSString *)action dictionary:(NSDictionary<NSString *,id> *)dictionary {
NSLog(@"original objc delegateMethod, called from %@", view);
}
-(void)invokeDelegate {
if (_delegate) {
// you can double check if the delegate is really an id<ProtocolName>
if ([_delegate conformsToProtocol:@protocol(ObjectiveCDelegate)]) {
// well you don't know if delegateMethod was implemented, it was optional
// so you have to check,
// indeed it's implemented above, but it is safe this way.
if ([_delegate respondsToSelector:@selector(delegateMethod:view:action:dictionary:)]) {
//now you can call it safely
[_delegate delegateMethod:0 view:@"original ObjectiveCConformingClass" action:@"a" dictionary:@{@"key":@"value"}];
}
}
} else {
NSLog(@"original ObjectiveCConformingClass delegate is nil");
}
}
@end
到目前为止,它在objective-c 中工作
现在在swift中,您甚至可以在扩展中使用委托
extension ObjectiveCConformingClass {
func extensionMethod() {
if ((delegate) != nil) {
if ((delegate?.responds(to: #selector(delegateMethod(_:view:action:dictionary:))))!) {
delegate?.delegateMethod?(1,view: "extension ObjectiveCConformingClass",action: "world",dictionary: ["foo":"bar"])
}
} else {
print("extension ObjectiveCConformingClass: delegate is nil")
}
}
// following will make you extreme trouble..
// see the missing _ so this is a different method then the objc variant
// its selector is #selector(delegateMethod(index:view:action:dictionary:)
func delegateMethod(index: Int, view: String, action: String, dictionary: [String : Any]) {
print("swift extension func delegateMethod, called from",view)
}
// #selector() is heavily confused what method to select when uncommented
// because selector is #selector(delegateMethod(_:view:action:dictionary:)
// which is declared in objc and can not be directly extended in swift
//func delegateMethod(_ index: Int, view: String, action: String, dictionary: [String : Any]) {
// print("swift extension func delegateMethod, called from",view)
//}
}
让我们检查子类化时swift扩展是否正常工作。
class ClassOtherName : ObjectiveCConformingClass {
func subclassMethod() {
if (delegate != nil) {
// you still don't know if the method was implemented, so check
if ((delegate?.responds(to: #selector(delegateMethod(_:view:action:dictionary:))))!) {
delegate?.delegateMethod?(1, view:"subclass ClassOtherName", action: "action", dictionary: ["key" : "value"])
} else {
print("delegate seems not conforming to protocol")
}
} else {
print("subclass ClassOtherName delegate is nil")
}
}
// of course you can override in subclasses, even if this was a super protocol method
// see the difference.. _ as argument used here
// because Overriding non-@objc declarations from extensions is not supported
override func delegateMethod(_ index: Int, view: String, action: String, dictionary: [String : Any]) {
print("override func delegateMethod, called from",view)
}
}
让我们测试
let a = ObjectiveCConformingClass() //extended version
a.extensionMethod() // extension ObjectiveCConformingClass: delegate is nil
//a.subclassMethod() // does not exist in ObjectiveCConformingClass
a.invokeDelegate() // original ObjectiveCConformingClass delegate is nil
let o = ClassOtherName() // subclassed version of extension
o.delegate = a
o.extensionMethod() // original objc delegateMethod, called from extension ObjectiveCConformingClass
o.subclassMethod() // original objc delegateMethod, called from subclass ClassOtherName
o.invokeDelegate() // original objc delegateMethod, called from original ObjectiveCConformingClass
o.delegate = nil
o.extensionMethod() // extension ObjectiveCConformingClass: delegate is nil
o.subclassMethod() // subclass ClassOtherName delegate is nil
o.invokeDelegate() // original ObjectiveCConformingClass delegate is nil
o.delegate = o //aka o == self
o.extensionMethod() // override func delegateMethod, called from extension ObjectiveCConformingClass
o.subclassMethod() // override func delegateMethod, called from subclass ClassOtherName
o.invokeDelegate() // override func delegateMethod, called from original ObjectiveCConformingClass
希望这不会太令人困惑,但你可以看到谁在呼唤谁,被召唤的是什么。