In Objective-C I'm used to declaring properties that connect to Interface Builder with
@property (nonatomic, weak) IBOutlet UIView *myView;
Now I have a class that uses the new XCode nullability attributes. To preserve compatibility with Swift, what nullability attribute should an IBOutlet
have? According to Apple's "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.
So does this mean the outlet should be declared nonnull
in Objective-C?
Null unspecified: bridges to a Swift implicitly-unwrapped optional. This is the default. Non-null: the value won't be nil ; bridges to a regular reference. Nullable: the value can be nil ; bridges to an optional. Non-null, but resettable: the value can never be nil when read, but you can set it to nil to reset it.
IBOutlet is a keyword which is added to a variable declaration. It's an indicator. It does not affect the declaration in any way. However, when the Interface Builder sees it, it will allows a programmer to set this variable through the “outlet” mechanism inside Interface Builder.
If your class is written in Swift, you can't use a non optional property because otherwise the compiler is going to complain that the property is never initialized. That's why Apple recommends to declare it as an implicitly unwrapped optional, because once your object has been initialized, you know for sure that the property contains a value (unless you have a dangling outlet, which can happen by the way...)
When exporting from Objective-C, you can mark it as nonnull
and it will appear in Swift as a non optional property which is fine in that case. Note that you can't use both nonnull
and weak
.
So you can either do :
@property (nonatomic, strong, nonnull) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet var subview: UIView
or
@property (nonatomic, weak, nullable) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet weak var subview: UIView?
If for some reason you still want the property to be exported to Swift as an implicitly unwrapped optional, you can mark the property as null_resettable
or null_unspecified
. That's not really what they are meant for but it will still produce the desired result. See this blog post for more on these annotations.
@property (nonatomic, weak, null_unspecified) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet weak var subview: UIView!
The declaration of weak
implies that the property is nullable. Therefore this works
@property (nonatomic, weak, nullable) IBOutlet UIView *contentView;
Declaring the property nonnull
gives an error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With