简体   繁体   English

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

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

I've seen lots of questions regarding implementing Obj-C protocols in Swift, but not so much the other way around, and I haven't seen this specifically. 我已经看到很多关于在Swift中实现Obj-C协议的问题,但其他方面并没有那么多,我没有具体看到这一点。

I am using a mixed Obj-C / Swift codebase. 我使用的是混合的Obj-C / Swift代码库。 I have a Swift protocol defined as follows: 我有一个Swift协议定义如下:

NamedItem.swift NamedItem.swift

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

I have an existing Objective-C class that currently has its own name property: 我有一个现有的Objective-C类,它目前有自己的name属性:

MyObjcClass.h MyObjcClass.h

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

I have a couple other classes that have a name property, so obviously I'd like to associate them all with a protocol instead of typecasting to a bunch of different types. 我还有一些其他具有name属性的类,所以显然我想将它们全部与协议相关联,而不是将它们转换为一堆不同的类型。 Now, if I try to switch my Obj-C class from having its own property to implementing the Swift protocol: 现在,如果我尝试将我的Obj-C类从拥有自己的属性切换到实现Swift协议:

MyObjcClass.h MyObjcClass.h

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

@interface MyObjcClass : NSObject
@end

MyObjcClass.m MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

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

This works great, in my other Objective-C classes , but if I try to access the name property from a Swift class : 在我的其他Objective-C类中很有 ,但是如果我尝试从Swift类访问name属性:

SomeSwiftClass.swift SomeSwiftClass.swift

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

I get the following error: 我收到以下错误:

Value of type 'MyObjcClass' has no member 'name' “MyObjcClass”类型的值没有成员“name”

If I don't remove the existing @property declaration from MyObjcClass.h and omit the @synthesize statement everything builds correctly. 如果我不删除现有@property从申报MyObjcClass.h并省略@synthesize声明一切正确的基础之上。 Which seems weird and wrong - If you adopt a Objc-C protocol from an Obj-C class you don't have to re-define the property, just the @synthesize statement is sufficient. 这看起来很奇怪和错误 - 如果您从Obj-C类采用Objc-C协议,您不必重新定义属性,只需@synthesize语句就足够了。

I've tried defining the Swift protocol about every way I could think of and have been able to find suggestions about, but I haven't been able to get around this. 我已经尝试过关于我能想到的各种方式来定义Swift协议,并且能够找到有关的建议,但是我无法解决这个问题。

So, what is the correct way to implement a Swift protocol property (maybe specifically a read-only property?) in an Objective-C class such that another Swift class can access it? 那么,在Objective-C类中实现Swift协议属性(可能特别是只读属性?)的正确方法是什么,以便另一个Swift类可以访问它? Do I really have to re-declare the property in the Obj-C header? 真的必须在Obj-C头中重新声明属性吗? I know I could always give it up and just define the protocol in Objective-C, but... Swift is the future! 我知道我总是可以放弃它,只是在Objective-C中定义协议,但...... Swift是未来! (or something like that...) (或类似的东西...)

// MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

This declaration isn't visible to Swift. Swift看不到此声明。 Move the protocol conformance clause <NamedItem> to the class's header file. 将协议一致性子句<NamedItem>到类的头文件中。

// MyObjCClass.h

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

@interface MyObjcClass : NSObject <NamedItem>
@end

As you commented, the Swift compiler still says that myObj does not have a property name . 正如您所评论的那样,Swift编译器仍然说myObj没有属性name This is quite strange. 这很奇怪。 Note that 注意

let myObj = MyObjcClass() as NamedItem
myObj.name

compiles fine. 编译好。

Ok, managed to get a working solution with some suggestions from JoshCaswell and this blog post. 好的,设法得到一个有效的解决方案,其中包含JoshCaswell博文的一些建议。

Classes now look as follows: 类现在看起来如下:

NamedItem.swift NamedItem.swift

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

MyObjcClass.h MyObjcClass.h

@protocol NamedItem;

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

MyObjcClass.m MyObjcClass.m

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

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

Usage now looks like: 用法现在看起来像:

SomeSwiftClass.swift SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.asNamedItem.name

Not as squeaky clean as I'd like, but it's better than a bunch of warnings or admitting defeat and re-writing the protocol in Objective-C. 不像我想的那样干净利落,但它比一堆警告更好,或者承认在Objective-C中失败和重写协议。 (I dunno, maybe it's not... but it's what I went with). (我不知道,也许不是......但这就是我的意思)。

Hope that helps someone else. 希望能帮助别人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM