Tune your header file Part 2: Nullability
In the first post I put the focus on the initializers, in this post I would like to put the 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, and 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
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 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
It works together with generics and applicable for the method parameters, not just the return values.
- (void)startPopulateDrawNumbersWithCompletionHandler:(void (^_Nonnull)(BOOL wasSuccessfull, NSArray
And 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 underscore you can use before the type definition, but after the type definition (like NSArray) you can use only the underscored version. Unfortunately blocks a are a quite picky about this. You can find a good set of different definition here: http://stackoverflow.com/a/33682230/3074959
What to consider and decide
Although you can either just ignore this advise, or try to cheat a little bit with
NS_ASSUME_NONNULL_END macros, if you want to implement the nullability in your header file, then be prepared to challenge all of your not primitive type properties and the methods 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. Which means that ALL of your pointer 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 the error or malfunction in cases when nil passed or set up for the variable.
If you think about migrate your existing code to Swift, which needs to be done soon or later, you have already one step closer to figure out, which variable need to be an optional and which not.