Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should an IBOutlet property be marked nullable or nonnull?

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?

like image 275
bcattle Avatar asked Jul 28 '16 18:07

bcattle


People also ask

What is nullable 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.

What is IBOutlet?

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.


2 Answers

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!
like image 91
deadbeef Avatar answered Oct 19 '22 22:10

deadbeef


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.

like image 33
bcattle Avatar answered Oct 19 '22 22:10

bcattle