Swift 类的 Objective-c 协议。无法识别的方法

Posted

技术标签:

【中文标题】Swift 类的 Objective-c 协议。无法识别的方法【英文标题】:Objective-c protocol to Swift class. unrecognized method 【发布时间】:2015-01-27 07:27:06 【问题描述】:

我正在尝试将一些代码从 Objective-c 迁移到 Swift,但是当我想使 Swift 类符合 Objective-c 协议并从 objetive-c 类访问该类时,我在开始时遇到了问题。我做错了什么,但我没有看到。

用于测试的Objective-c协议和obj-c类(test_class.h)

#import <Foundation/Foundation.h>

@protocol test_delegate

-(void)returnData:(NSString*)data InMethod:(NSString*)method;
@end

@interface test_class : NSObject

@property (weak, nonatomic) id<test_delegate> delegate;
-(void)sendData:(NSString * )data;
@end

Objective-c 实现

#import "test_class.h"

@implementation test_class

-(id) init
    self = [super init];
    if (self != nil)
        self.delegate= nil;
    
    return self;

-(id) initWithDelegate:(id<test_delegate>) delegate
    self = [super init];
    if (self != nil)
        self.delegate = delegate;

    
    return self;



-(void)sendData:(NSString *)data

    [self.delegate returnData:data InMethod:@"method test"];

@end

Objetive-c 桥文件

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "test_class.h"

Swift 文件 (FirstViewController.swift)

import UIKit

class FirstViewController: UIViewController, test_delegate 

    var test : test_class!

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        test = test_class()
        test.delegate=self
        test.sendData("show in log")
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    func returnData(data: String!, inMethod method: String!) 
        NSLog(data)
    



最后编译错误给了我

2015-01-27 08:21:05.787 Test[4566:51164] -[Test.FirstViewController returnData:InMethod:]: unrecognized selector sent to instance 0x7fa6abd0aa20
2015-01-27 08:21:05.792 Test[4566:51164] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Test.FirstViewController returnData:InMethod:]: unrecognized selector sent to instance 0x7fa6abd0aa20'

此代码仅使用 Obj-c 类可以正常工作。我做错了什么?

使用 Xcode 6.1.1 和部署目标 ios 8.0

提前谢谢你。

更新: 当从 Objective-C 协议实现某些方法时,Swift 有一个奇怪的行为:参数的名称必须以开头的一个小字母开头,否则,编译器会给你一个编译时错误,如果不是,给你一个运行时错误。

我发现的唯一解决方案是这样修改objective-c协议方法定义:

@protocol test_delegate

-(void)returnData:(NSString*)data InMethod:(NSString*)method;
@end

到:

@protocol test_delegate

-(void)returnData:(NSString*)data inMethod:(NSString*)method;
@end

进行此更改,它运行完美。

如果有人对此行为有答案,欢迎发布并解释为什么会发生这种情况。

更新 2: 感谢@Adam Freeman 指出另一个关于类名和变量名的 Swift 奇怪问题。在此处复制(经他的许可)代码:

要注意的另一件事是,如果您的协议委托方法将其类作为其参数之一。使用这个例子:

#import <Foundation/Foundation.h>

@class TestClass;
@protocol TestDelegate
-(void)TestClass:(TestClass*)TestClass returnData:(NSString*)data inMethod:(NSString*)method;
@end

@interface TestClass : NSObject

@property (weak, nonatomic) id<TestDelegate> delegate;
-(void)sendData:(NSString * )data;
@end

这将导致在您的 Swift 代码中发现 TestClass 出现问题。解决方法是:

#import <Foundation/Foundation.h>

@class TestClass;
@protocol TestDelegate
-(void)testClass:(TestClass*)testClass returnData:(NSString*)data inMethod:(NSString*)method;
@end

@interface TestClass : NSObject

@property (weak, nonatomic) id<TestDelegate> delegate;
-(void)sendData:(NSString * )data;
@end

顺便说一句,Swift 规范规定,类和委托等内容应以大写字母开头,方法和参数名称应以小写字母开头。

【问题讨论】:

检查InMethod(Objective-C)和inMethod(Swift)的大小写。 感谢您的回答 grimxn。你说的是真的,但是如果你尝试大写 inMethod(swift) xcode 编译器会给你一个错误。除了更改协议方法或制作中间对象之外,没有其他解决方案。我会在主帖中更新 【参考方案1】:

变化:

func returnData(data: String!, inMethod method: String!) 

func returnData(data: String!, InMethod method: String!) 

它应该可以工作。在inMethod 中使用大写字母。

【讨论】:

【参考方案2】:

我遇到的另一件事要注意,这篇文章帮助我修复了(thanX!),其他人可能遇到的问题是,如果您的协议委托方法将其类作为其参数之一。比如==>

#import <Foundation/Foundation.h>

@class TestClass;
@protocol TestDelegate
-(void)TestClass:(TestClass*)TestClass returnData:(NSString*)data inMethod:(NSString*)method;
@end

@interface TestClass : NSObject

@property (weak, nonatomic) id<TestDelegate> delegate;
-(void)sendData:(NSString * )data;
@end

这将导致在您的 Swift 代码中发现 TestClass 出现问题。解决方法是:

#import <Foundation/Foundation.h>

@class TestClass;
@protocol TestDelegate
-(void)testClass:(TestClass*)testClass returnData:(NSString*)data inMethod:(NSString*)method;
@end

@interface TestClass : NSObject

@property (weak, nonatomic) id<TestDelegate> delegate;
-(void)sendData:(NSString * )data;
@end

顺便说一句,Swift 规范规定类和委托等内容应以大写字母开头,方法和参数名称应以小写字母开头。我知道这很挑剔,但根据 Apple 的规范,test_class 确实应该是 TestClass。

【讨论】:

在您允许的情况下,我将用您的 cmets 更新主帖。我认为这是 Swift 语法的另一个“奇怪”案例,就像主要问题一样,很高兴了解更多关于它的信息。谢谢! 现在它在主帖中。您能在这里解释一下您使用的是什么版本的 sdk、xcode 和 swift 吗?为了更好地了解所有情况:)。如果您想更改任何内容,请随时在这篇文章中告诉我,我会更新它(或自己做!)

以上是关于Swift 类的 Objective-c 协议。无法识别的方法的主要内容,如果未能解决你的问题,请参考以下文章

来自符合协议的未知类的 Swift init

我可以防止将扩展导出到 Objective-C 的 Swift 标头吗?

匹配来自 Objective-C 协议实例的 Swift 协议

无法将符合协议的 Objective-C 类分配给具有 Swift 协议的属性

Swift 中的 Objective-C 协议

在 Swift 上委托 Objective-C 协议