无法将符合协议的 Swift 类的实例分配给需要该协议的 Objective-C 属性

Can't assign instance of a Swift class conforming to a protocol to an Objective-C property expecting that protocol

提问人:HangarRash 提问时间:11/4/2023 更新时间:11/4/2023 访问量:48

问:

我正在尝试在一个主要是 Objective-C 的项目中使用 Swift 类。这与 一起使用有关。UIContentConfigurationUITableViewCell

这是我的 Swift 代码:

@objc class MyCellConfiguration: NSObject, UIContentConfiguration {
    let label: String

    @objc init(label: String) {
        self.label = label
    }

    func makeContentView() -> UIView & UIContentView {
        return MyCellContent(self)
    }

    func updated(for state: UIConfigurationState) -> Self {
        return self
    }
}

class MyCellContent: UIView, UIContentView {
    // Implementation of this class is not relevant to the question
}

当我尝试在某些 Objective-C 代码中设置单元格时,我收到编译器警告。如果我忽略该警告,则当到达代码时,应用程序将在运行时挂起。

下面是 Objective-C 代码:

#import "MyApp-Swift.h" // The bridging header is being imported

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:key forIndexPath:indexPath];

MyCellConfiguration *config = [[MyCellConfiguration alloc] initWithLabel:@"Some Label"];
cell.contentConfiguration = config; // warning here

我收到的编译器警告是:

从不兼容的类型“MyCellConfiguration *__strong”分配给“id<UIContentConfiguration> _Nullable”

为什么编译器无法识别出符合 Objective-C 代码中的协议?MyCellConfigurationUIContentConfiguration

Swift 代码可以很好地识别一致性。例如,以下代码编译时没有问题:

let cell = UITableViewCell(style: .default, reuseIdentifier: "foo")
cell.contentConfiguration = MyCellConfiguration(label: "foo")

我在 macOS 13.6.1 上使用 Xcode 15.0。

Swift Objective-C UIKit 协议

评论


答:

4赞 Sweeper 11/4/2023 #1

一些观察:

  • UIContentConfiguration 的文档页没有可以使用“语言:Swift”选择器选择的 Objective-C 版本。Objective-C 版本在这里
  • UIContentConfiguration不会像其他 Objective-C 协议那样继承,当它们被导入 Swift 时。NSObjectProtocol
  • Swift 版本有一个返回交集类型的方法,该类型不能在 Objective-C 中表示。(Objective-C 版本返回UIContentConfigurationmakeContentView__kindof UIView<UIContentView> *)

这些都表明,在 Swift 中,协议与它的 Objective-C 版本完全不同。仅仅在 Swift 中遵循它并不意味着你在 Objective-C 中遵循它。UIContentConfiguration

您还可以在其他相关类型(如 和)中看到类似的模式。UIContentViewUIConfigurationState

事实上,尝试在 Swift 中设置一个实例,看看 Objective-C 这边会发生什么。尝试在 Objective-C 中打印出来。输出不是 !contentConfigurationMyCellConfiguration[cell.contentConfiguration class]MyCellConfiguration

总而言之,你必须在 Objective-C 中重新实现 Objective-C 版本,或者你可以在 Swift 中添加一个这样的方法:UIContentConfiguration

@objc
func addToCell(_ cell: UITableViewCell) {
    cell.contentConfiguration = self
}
UITableViewCell *cell = ...;
MyCellConfiguration *config = [[MyCellConfiguration alloc] initWithLabel:@"Some Label"];
[config addToCell:cell];

评论

0赞 HangarRash 11/4/2023
好!我注意到 Swift 和 ObjC 之间奇怪的文档链接,但我没有注意到 Swift 版本的重要性或缺乏一致性。非常有趣,即使我需要更多地研究这些细节才能完全理解。我刚刚尝试了你的工作,它工作得很好。就在 10 分钟前,我完成了在 Objective-C 中重新实现的测试,以避免这个问题。我应该更有耐心。UIContentConfigurationNSObjectProtocolMyCellConfiguration