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

时间:2019-01-23 19:39:36

标签: objective-c swift compiler-errors swift-protocols objective-c-swift-bridge

我已经看到了许多有关在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类中访问名称属性

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是未来! (或类似的东西...)

2 个答案:

答案 0 :(得分: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没有属性name。这很奇怪。请注意

let myObj = MyObjcClass() as NamedItem
myObj.name

编译良好。

答案 1 :(得分:1)

好吧,设法从JoshCaswellthis博客文章中获得了一些建议,并找到了可行的解决方案。

现在的类如下:

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

希望对别人有帮助。