In the first post, I put the focus on the initializers. In this post, I would like to put nullability into the spotlight. I would also explain why is it a good practice and how it will help you migrate your existing Objective-C code into Swift.
The idea behind using the nullable/nonnull keyword is to protect our code against the accidental
nil values, which might crash our app in runtime. As I mentioned in the Embrace Compile Time Errors post, it is better that the developer has early warning about the problem, so it won’t escalate to the runtime error.
Nonnull keywords we, as developers, can clearly and explicitly define that the class property or the method variables and return value can be nil or not. Examples:
@property (weak, nonatomic, nullable) id progressDelegate;
For an object type property, it is quite easy to use. Just add the nullable/nonnull for the property attributes.
@property (unsafe_unretained, nonatomic) BOOL isAllModelParsed;
For the primitive types, there is no sense or need to add nullability.
- (nullable instancetype)init;
As you can see even the initializer return value (instancetype) can have the nullability attribute.
- (nullable instancetype)initWithModelControllers:(nullable NSArray *) models NS_DESIGNATED_INITIALIZER;
It works together with generics and is applicable for the method parameters, not just the return values.
- (void)startPopulateDrawNumbersWithCompletionHandler:(void (^_Nonnull)(BOOL
wasSuccessfull, NSArray * _Nullable numbers))callback;
And it can be applied on the blocks as well. Please note the use of underscore (_Nonnull/_Nullable). Essentially, this is same. The only difference is that without the underscore, you can use it before the type definition, but after the type definition, (like NSArray) you can use only the underscored version. Unfortunately, blocks are quite picky about this. You can find a good set of different definitions here.
What to Consider and Decide About Nullability
Although you can either ignore this advice, or try to cheat a little bit with
NS_ASSUME_NONNULL_END macros, if you want to implement nullability in your header file, then be prepared to challenge all of your non-primitive types properties and the method parameters with the return type as well.
If you set up even one variable with the nullability, clang will warn you to with the “Pointer is missing nullability type specifier” message. That means that ALL of your pointers in the header file need to have a clearly defined nullability.
When the nullability properly set up and defined for all of our classes, it helps us in the early detection of errors or malfunction in cases when nil passed or set up for the variable.
If you're thinking about migrating your existing code to Swift, which needs to be done soon or later, you're already one step closer to figuring out which variables need to be Optional and which don't.