从另一个 Swift class 访问在 Obj-C class 中实现的 Swift 协议 属性

Accessing Swift protocol property implemented in an Obj-C class from another Swift class

我看到很多关于在 Swift 中实施 Obj-C 协议的问题,但相反的问题并不多,我还没有具体看到这个。

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

NamedItem.swift

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

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

MyObjcClass.h

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

我有几个其他 classes 有一个 name 属性,所以很明显我想把它们都与一个协议相关联而不是类型转换成一堆不同种类。现在,如果我尝试将我的 Obj-C class 从拥有自己的 属性 切换到实现 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 classes 中,但是如果我尝试访问名称 属性 来自 Swift class:

SomeSwiftClass.swift

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

我收到以下错误:

Value of type 'MyObjcClass' has no member 'name'

如果我不从 MyObjcClass.h 中删除现有的 @property 声明并省略 @synthesize 声明,一切都会正确构建。这看起来很奇怪而且是错误的——如果你从 Obj-C class 采用 Objc-C 协议,你不必 re-define 属性,只需 @synthesize 语句就足够了。

我尝试过定义 Swift 协议的每一种我能想到的方式,并且已经找到相关建议,但我无法解决这个问题。

那么,在 Objective-C 中实现 Swift 协议 属性(也许具体是 read-only 属性?)的正确方法是什么? =90=] 这样另一个 Swift class 可以访问它吗?我 真的 必须 re-declare Obj-C header 中的 属性 吗?我知道我总是可以放弃它并只在 Objective-C 中定义协议,但是...... Swift 是未来! (或类似的东西...)

// MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

此声明对 Swift 不可见。将协议一致性条款 <NamedItem> 移至 class 的头文件。

// MyObjCClass.h

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

@interface MyObjcClass : NSObject <NamedItem>
@end

正如您所说,Swift 编译器仍然说 myObj 没有 属性 name。这很奇怪。注意

let myObj = MyObjcClass() as NamedItem
myObj.name

编译正常。

好的,根据 and this 博客 post 的一些建议,设法获得了一个可行的解决方案。

类现在看起来如下:

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 中重写协议要好。 (我不知道,也许不是……但我就是这么做的)。

希望对其他人有所帮助。