4

我已经看到了很多关于在 Swift 中实现 Obj-C 协议的问题,但反过来却没有,而且我还没有具体看到这一点。

我正在使用混合的 Obj-C / Swift 代码库。我有一个定义如下的 Swift 协议:

NamedItem.swift

@objc protocol NamedItem {
    var name: String { get }
}

我有一个现有的 Objective-C 类,它目前有自己的name属性:

MyObjcClass.h

@interface MyObjcClass : NSObject
@property (nonatomic, strong, readonly) NSString* name;
@end

我还有其他几个具有name属性的类,所以显然我想将它们都与一个协议相关联,而不是对一堆不同的类型进行类型转换。现在,如果我尝试将我的 Obj-C 类从拥有自己的属性切换到实现 Swift 协议:

MyObjcClass.h

@protocol MyObjcProtocol
@property (nonatomic, strong, readonly) NSString* place;
@end

@interface MyObjcClass : NSObject
@end

MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

@implementation MyObjcClass
@synthesize name = _name;
@synthesize place = _place;
@end

这在我的其他 Objective-C 类中效果很好,但是如果我尝试从 Swift 类中访问 name 属性:

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.name // error
myObj.place // no problem

我收到以下错误:

“MyObjcClass”类型的值没有成员“名称”

如果我不删除现有@property声明MyObjcClass.h并省略该@synthesize语句,一切都会正确构建。这似乎很奇怪和错误 - 如果您从 Obj-C 类中采用 Objc-C 协议,则不必重新定义属性,只需@synthesize声明就足够了。

我已经尝试以我能想到的所有方式定义 Swift 协议,并且能够找到有关的建议,但我无法解决这个问题。

那么,在 Objective-C 类中实现 Swift 协议属性(可能是只读属性?)以便另一个 Swift 类可以访问它的正确方法是什么?我真的必须在 Obj-C 标头中重新声明该属性吗?我知道我总是可以放弃它,只在 Objective-C 中定义协议,但是...... Swift 是未来!(或类似的东西...)

4

2 回答 2

2
// MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

这个声明对 Swift 是不可见的。将协议一致性子句<NamedItem>移至类的头文件。

// MyObjCClass.h

// Required for visibility of the protocol
#import "MyProject-Swift.h"

@interface MyObjcClass : NSObject <NamedItem>
@end

正如您评论的那样,Swift 编译器仍然说myObj没有 property name。这很奇怪。注意

let myObj = MyObjcClass() as NamedItem
myObj.name

编译得很好。

于 2019-01-23T19:47:01.890 回答
1

好的,通过JoshCaswell这篇博文的一些建议,设法得到了一个可行的解决方案。

类现在如下所示:

NamedItem.swift

@objc protocol NamedObject {
    var name: String { get }
}

MyObjcClass.h

@protocol NamedItem;

@interface MyObjcClass : NSObject
- (id<NamedItem>)asNamedItem;
@end

MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@synthesize name = _name;

- (id<NamedItem>)asNamedItem
{
    return self;
}
@end

用法现在看起来像:

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.asNamedItem.name

不像我想要的那样干净利落,但它比一堆警告或承认失败并在 Objective-C 中重写协议要好。(我不知道,也许不是……但这就是我的选择)。

希望对其他人有所帮助。

于 2019-01-23T20:54:21.310 回答