According to the Xcode release notes, Apple has been \"auditing\" their existing APIs to remove implicitly unwrapped optionals. That means that instead of T!
, t
Xcode 6.3 added official support for annotating nullability in Objective-C.
The nullability of a value can be declared by annotating the type with the keywords __nullable
, __nonnull
and __null_unspecified
(the default). In properties and methods the keywords are nullable
, nonnull
and null_unspecified
.
Examples from the Xcode release notes
- (void)registerNib:(nonnull UINib *)nib
forCellReuseIdentifier:(nonnull NSString *)identifier;
- (nullable UITableViewCell *)cellForRowAtIndexPath:(nonnull NSIndexPath)indexPath;
@property (nonatomic, readwrite, retain, nullable) UIView *backgroundView;
null_unspecified
(which translates to T!
) is the default for all existing code. A useful feature is the ability to change the default for sections of your API.
NS_ASSUME_NONNULL_BEGIN
// nonnull is the default here
NS_ASSUME_NONNULL_END
This removes a lot of noise, since methods that accept and handle nil usually are the exception, not the rule. Personally, I would use this for all audited APIs.
null_resettable
is an additional annotation that is used for the uncommon case where you can set a property to nil, but it will never be nil (because it resets to a default value).
@property (nonatomic, retain, null_resettable) UIColor *tintColor;
Personally, I would avoid this behavior for new code. The hybrid nature of such properties isn't a good fit for Swift.
Xcode 7 adds support for annotating generic types in Objective-C.
NSArray
, NSSet
and NSDictionary
(which are automatically bridged to Swift's Array
, Set
and Dictionary
can be annotated with the type of their contents.
@property NSArray *stringArray;
@property NSSet *stringSet;
@property NSDictionary *stringDict;
There's also the __kindof
keyword that tells the Objective-C compiler to be less strict and allow downcasting. But it doesn't affect the Swift side.
@interface MyArray1<__covariant T> : NSObject
- (void)addObject:(T)object;
@end
@interface MyArray2<__covariant T : NSObject *> : NSObject
- (void)addObject:(T)object;
@end
@interface MyArray3<__covariant T : id> : NSObject
- (void)addObject:(T)object;
@end
The @implementation
doesn't know about T
and uses id
/NSObject *
/id
as it always did.