IBOutlet 属性 应该标记为可空还是非空?

Should an IBOutlet property be marked nullable or nonnull?

在 Objective-C 中,我习惯于使用

声明连接到 Interface Builder 的属性
@property (nonatomic, weak) IBOutlet UIView *myView; 

现在我有一个使用新的 XCode 可空性属性的 class。为了保持与 Swift 的兼容性,IBOutlet 应该具有什么可空性属性?根据 Apple 的“Using Swift with Cocoa and Objective-C”:

When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional. This way, you can let the storyboard connect the outlets at runtime, after initialization. When your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected.

那么这是否意味着插座应该在 Objective-C 中声明 nonnull

weak 的声明意味着 属性 可以为空。因此这有效

@property (nonatomic, weak, nullable) IBOutlet UIView *contentView;

声明 属性 nonnull 会出错。

如果你的 class 是用 Swift 写的,你不能使用非可选的 属性 因为否则编译器会抱怨 属性 是从未初始化。这就是为什么 Apple 建议将其声明为隐式解包可选,因为一旦您的对象被初始化,您就可以确定 属性 包含一个值(除非您有一个悬垂的出口,这可能会发生。 ..)

从 Objective-C 导出时,您可以将其标记为 nonnull,它将作为非可选 属性 出现在 Swift 中,这在这种情况下很好。请注意,您不能同时使用 nonnullweak.

所以你可以这样做:

@property (nonatomic, strong, nonnull) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet var subview: UIView

@property (nonatomic, weak, nullable) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet weak var subview: UIView?

如果出于某种原因您仍然希望将 属性 作为隐式展开的可选项导出到 Swift,您可以将 属性 标记为 null_resettablenull_unspecified。这并不是它们真正的目的,但它仍然会产生预期的结果。有关这些注释的更多信息,请参阅 this blog post

@property (nonatomic, weak, null_unspecified) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet weak var subview: UIView!