从Swift插件访问Objective-C NSDocument子类的实例属性?
目标是编写一个Swift插件,它可以访问Objective-C NSDocument子类的公共实例属性。主要的应用程序是Objective-C。该插件的目的是快速 主应用程序具有公共Objective-C文档界面:从Swift插件访问Objective-C NSDocument子类的实例属性?,objective-c,macos,plugins,swift3,Objective C,Macos,Plugins,Swift3,目标是编写一个Swift插件,它可以访问Objective-C NSDocument子类的公共实例属性。主要的应用程序是Objective-C。该插件的目的是快速 主应用程序具有公共Objective-C文档界面: @interface ObjcNSDocument : NSDocument @property (nonatomic, readwrite) NSString *markdown; @property (nonatomic, readonly) NSString *html;
@interface ObjcNSDocument : NSDocument
@property (nonatomic, readwrite) NSString *markdown;
@property (nonatomic, readonly) NSString *html;
@end
合理的Swift对应物似乎是:
public class SwiftNSDocument: NSDocument {
public var markdown: String = ""
public var html: String = ""
}
以下Swift代码检索当前NSOK文档。然而,铸造失败
public func doFilter() {
let dc = NSDocumentController.shared()
if let document: NSDocument = dc.currentDocument {
print("document.displayName = \(document.displayName)") // works OK
let markdownSource = document as! SwiftNSDocument // FAIL: cannot cast as
}
}
虽然我要求这是一般性的,但我的特殊测试用例是重写Objective-C插件,使其尽可能接近纯Swift
理想情况下,解决方案不需要包含来自应用程序的任何Objective-C代码。什么是可能的,即使不理想
额外观察
对于正在工作的Objective-C插件,插件项目中不包括应用程序的NSDocument子类.h
文件
相反,Objective-C插件只有作为NSObject子类的单个相关属性
@protocol MarkdownSource <NSObject>
@property (readonly) NSString *markdown;
@end
其中Object-C中的id
将是SwiftAny
。我尝试过各种向下投射,如:
let markdownSource: MarkdownSource = (nsdocument as Any) as MarkdownSource
let markdown: String = markdownSource.markdown
到目前为止,我还无法使用Swift中的一个所需属性将NSDocument子类向下转换为任何NSObject子类。转换失败,因为文档的类型是
ObjcNSDocument
,而不是SwiftNSDocument
。目前,Swift中没有任何设施可以提供Objective-C级可以衔接的Swift级,反之亦然。您必须在插件中的某个地方包含Objective-C类的声明(通过包含标题或其他方式)。尝试只使用Swift的目的是什么?@itai ferber为什么只使用Swift?了解什么是Objective-C最基本的需求,并用Swift编写新的代码。你在Objective-C中所做的角色转换碰巧有效,但原因是错误的。从技术上讲,这不是一个有效的强制转换,因为您的Objective-C类实际上不符合MarkdownSource
协议;它之所以有效,是因为Objective-C在这种情况下是不安全的,而且足够动态-获取MarkdowSource.markdown
转换为[MarkdowSource markdown]
,而文档
恰好响应了它,所以它有效。如果我执行((id)someRandomObject.).markdown
,强制转换将盲目成功,但方法调用将失败。Swift不允许您进行这些无效强制转换,因为它只允许您进行方法调用,它可以静态地(尽可能多地)保证它们会成功。(是的,您可以使用Objective-C运行时来做某些事情,但这避免了静态安全性);dr:以这种方式施法是无效的,所以斯威夫特不会让你这么做。
public class MarkdownSource: NSObject {
public var markdown: String = ""
}
let markdownSource: MarkdownSource = (nsdocument as Any) as MarkdownSource
let markdown: String = markdownSource.markdown