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 协议。无法识别的方法的主要内容,如果未能解决你的问题,请参考以下文章
我可以防止将扩展导出到 Objective-C 的 Swift 标头吗?
匹配来自 Objective-C 协议实例的 Swift 协议