0

我正在尝试通过对所述类的快速扩展来符合 Objective-C 类上的 Objective-C 委托方法。问题是在下面的快速扩展中定义此函数的主体时,我没有提供自动完成选项。我不得不从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 类中执行它,它工作正常。任何想法为什么它不起作用?或者如果这甚至是可能的?

这里有一些相当相似的问题,它们要求不同的东西,所以对我没有帮助。(即不是重复的线程)

4

1 回答 1

0

阅读时花点时间。
将委托视为符合协议的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(可为空),这意味着你为什么想要它weak

@property (nonatomic, weak) id<ObjectiveCDelegate> delegate;

并且将成为您的委托的类(对象)必须符合此协议,因此您必须像以前一样在其接口中声明它。在完全美丽看起来像..

@interface ObjectiveCConformingClass : SuperClass <ObjectiveCDelegate>
@property (nonatomic, weak) id<ObjectiveCDelegate> delegate;
-(void)invokeDelegate; //for testing.
@end

因为上面的协议有可选的方法声明,所以当你没有实现它时它不会抛出警告。为避免在使用ClassName(object) 的类中使用委托时遇到麻烦,您需要检查委托属性是否不存在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中工作

现在,即使在扩展程序中,您也可以快速使用委托

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

希望这不会太令人困惑,但是您会看到谁在调用谁以及调用了什么。

于 2020-11-10T05:27:59.083 回答