【问题标题】:How to prevent circular reference when Swift bridging header imports a file that imports Hopscotch-Swift.h itselfSwift桥接头导入导入Hopscotch-Swift.h本身的文件时如何防止循环引用
【发布时间】:2014-10-29 11:53:26
【问题描述】:

我正在将 Swift 集成到一个现有的大型 Objective C 项目中,并且遇到了我认为的循环引用。

有问题的类如下:

目标 C 控制器

#import "Hopscotch-Swift.h"

@interface MyController : UIViewController<MyProtocol>
   ...
@end

Swift 协议

@objc protocol MyProtocol: NSObjectProtocol {
   ...
}

桥接头

#import "MyController.h"

此代码无法编译,因为Hopscotch-Swift.h 文件不会生成。

我认为这是由于循环引用错误,因为我可以将 Hopscotch-Swift.h 导入到 Hopscotch-Bridging-Header.h 中未包含的目标 c 标头中并且它工作正常。

是否有解决此问题的方法或者我应该向 Apple 提交雷达?

【问题讨论】:

  • 我看到了。这不完全一样,因为那个人试图阻止两个 obj-c 文件碰撞,而我试图将我的所有 swift 文件导入到运行我的 swift 文件所需的 obj-c 文件中。
  • 您是否提交了雷达文件或找到了解决方案?
  • 我可能会尝试 Jochen 的解决方案。到目前为止最好的解决方法是在 Objective C 中编写标题。我应该提交一个雷达但还没有时间。

标签: objective-c cocoa swift


【解决方案1】:

您可以在怀疑触发循环引用的 .h 文件中使用类似的内容:

#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif

【讨论】:

  • 但这就是 #import 所做的,为什么它比 #include 更好
  • 提交者在#import 方面遇到了问题。目前尚不清楚根本原因是什么。是的,您会期望 @#import 检测循环引用
【解决方案2】:

我尝试在 Objective-C 协议中使用 Swift 类时遇到了这个问题,该协议也由另一个 Swift 类实现。它散发着循环引用的味道,我猜想循环生成桥接头可能是个问题,而不是“正常”循环包含问题。

对我来说,解决方案是在协议声明之前使用前向声明:-

// don't include the MyProject-Swift.h header

// forward declaration of Swift classes used
@class SwiftClass;

@protocol MyProtocol <NSObject>
- (SwiftClass *)swiftClass;
@end

【讨论】:

  • 如果您在方法签名中需要 Swift 对象或协议,但您既不能从只被转发声明的类继承,也不能实现只被转发声明的协议,则转发声明可以工作。后一种情况就是问题所在。
【解决方案3】:

在您的情况下,前向声明应该可以工作。

在您的 .h 中:

@protocol MyProtocol;

@interface MyController : UIViewController<MyProtocol>

@end

在您的 .m 中:

#import "HopScotch-Swift.h"

来自How can I add forward class references used in the -Swift.h header? 和 Swift 互操作性指南:

如果您在 Swift 代码中使用自己的 Objective-C 类型,请确保在将 Swift 生成的标头导入要访问 Swift 的 Objective-C .m 文件之前为这些类型导入 Objective-C 标头代码来自。

【讨论】:

  • 这对我有用。万一它对其他人有帮助,经过大量搜索后导致我得到这个答案的编译器错误是:找不到'ProjectName-Swift.h'文件”和“无法导入桥接头'.../ProjectName-Bridging-页眉.h'。
  • 我不确定这对你有什么作用,@kleezy,因为you cannot forward declare a protocol that you implement in Objective-C。如果您尝试运行上面的代码,您将收到警告 Cannot find protocol definition for 'MyProtocol'
  • 同样,我在 Swift 中定义了一个协议,我在 Objective-C 中使用id &lt;Protocol&gt;,我不能在我的一生中声明这一点。删除(可能是不明智的)协议将是对应用程序的重大跨领域重写。
【解决方案4】:

前向声明本身对我不起作用。它编译时没有错误,但仍然有无法找到协议的警告。我将所有警告都视为错误,所以这还不够好。

我能够通过将协议实现移动到另一个类别标头来修复它。

所以这对我有用:

在我的 MyOtherSwiftFile.swift 中:

@objc protocol MyProtocol: class {
func viewController(didFinishEditing viewController: MyViewController)
}

在我的 MyViewController.h 中:

@interface MyViewController // Removed protocol implementation declaration here
@end

将 MyViewController+MyProtocol.h 添加到项目中,并将其放在那里:

@interface MyViewController (MyProtocol) <MyProtocol>
@end

如果您愿意,方法本身可以保留在原处。

实现上述内容并编译后,您会在代码中的某处收到编译器警告,要求 MyViewController 实现 MyProtocol。在该文件中,您将#import "MyViewController+MyProtocol.h"

【讨论】:

  • 这是一个绝妙的解决方案。谢谢。我认为这里的关键是能够导入-MyProtocol.h file 您在最后一步中将项目的-Swift.h 文件导入到这些文件中,其中需要导入-MyProtocol.h 文件...
  • 请注意,当您这样做时,您还必须明确地使用@implementation SomeClass (SomeProto) 实现类别,就像您只是在主实现中实现协议方法一样,编译器会很高兴,甚至在运行时工作(调用方法会成功),但是当您询问类实例 conformsToProtocol: 时,它会说 NO,除非它找到该类别的实现,这可能会在某些地方导致问题。
  • 同样使用这个技巧,Swift 不会看到你的类符合协议,因为你不能将 MyViewController+MyProtocol.h 导入到桥接头中,因为你回到了循环引用问题的全部内容.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 1970-01-01
相关资源
最近更新 更多