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

Jor*_*ndo 5 compiler-errors objective-c swift objective-c-swift-bridge swift-protocols

我见过很多关于在 Swift 中实现 Obj-C 协议的问题,但反之则不然,而且我还没有具体看到这一点。

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

命名项目.swift

@objc protocol NamedItem {
    var name: String { get }
}
Run Code Online (Sandbox Code Playgroud)

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

MyObjcClass.h

@interface MyObjcClass : NSObject
@property (nonatomic, strong, readonly) NSString* name;
@end
Run Code Online (Sandbox Code Playgroud)

我还有其他几个具有name属性的类,因此显然我想将它们全部与协议关联起来,而不是类型转换为一堆不同的类型。现在,如果我尝试将 Obj-C 类从拥有自己的属性切换为实现 Swift 协议:

MyObjcClass.h

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

@interface MyObjcClass : NSObject
@end
Run Code Online (Sandbox Code Playgroud)

MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

@implementation MyObjcClass
@synthesize name = _name;
@synthesize place = _place;
@end
Run Code Online (Sandbox Code Playgroud)

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

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.name // error
myObj.place // no problem
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

“MyObjcClass”类型的值没有成员“name”

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

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

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

Jor*_*ndo 2

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

类现在如下所示:

命名项目.swift

@objc protocol NamedObject {
    var name: String { get }
}
Run Code Online (Sandbox Code Playgroud)

MyObjcClass.h

@protocol NamedItem;

@interface MyObjcClass : NSObject
- (id<NamedItem>)asNamedItem;
@end
Run Code Online (Sandbox Code Playgroud)

MyObjcClass.m

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

- (id<NamedItem>)asNamedItem
{
    return self;
}
@end
Run Code Online (Sandbox Code Playgroud)

现在的用法如下:

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.asNamedItem.name
Run Code Online (Sandbox Code Playgroud)

虽然不像我想要的那么干净,但它比一堆警告或承认失败并用 Objective-C 重写协议要好。(我不知道,也许不是......但这是我所选择的)。

希望对其他人有帮助。