Skip to content

Instantly share code, notes, and snippets.

@sakrist
Last active April 22, 2020 06:40
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sakrist/f97499de2dd6687d6403 to your computer and use it in GitHub Desktop.
Save sakrist/f97499de2dd6687d6403 to your computer and use it in GitHub Desktop.
Objective-C Language Enhancements

Objective-C APIs can now express the “nullability” of parameters, return types, properties, variables, etc. For example, here is the expression of nullability for several UITableView APIs:

-(void)registerNib:(nonnull UINib *)nib forCellReuseIdentifier:(nonnull NSString *)identifier;
-(nullable UITableViewCell *)cellForRowAtIndexPath:(nonnull NSIndexPath)indexPath;
@property (nonatomic, readwrite, retain, nullable) UIView *backgroundView;

The nullability qualifiers affect the optionality of the Objective-C APIs when in Swift. Instead of being imported as implicitly-unwrapped optionals (e.g., UINib!), nonnull-qualified types are imported as non-optional (e.g., UINib) and nullable-qualified types are imported as optional (e.g., UITableViewCell?), so the above APIs will be seen in Swift as:

func registerNib(nib: UINib, forCellReuseIdentifier identifier: String)
func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell?
var backgroundView: UIView?

Nullability qualifiers can also be applied to arbitrary pointer types, including C pointers, block pointers, and C++ member pointers, using double-underscored versions of the nullability qualifiers. For example, consider a C API such as:

void enumerateStrings(__nonnull CFStringRef (^ __nullable callback)(void));

Here, the callback itself is nullable and the result type of that callback is nonnull. This API will be usable from Swift as:

func enumerateStrings(callback: (() -> CFString)?)

In all, there are three different kinds of nullability specifiers, which can be spelled with a double-underscore (on any pointer type) or without (for Objective-C properties, method result types, and method parameter types):

| Type qualifier spelling | Objective-C property/method spelling |Swift view |Meaning| |---|---|---|---|---| | __nonnull | nonnull | Non-optional, e.g., |UINib |The value is never expected to be nil (except perhaps due to messaging nil in the argument)| | __nullable | nullable | Optional, e.g., |UITableViewCell? |The value can be nil| |__null_unspecified |null_unspecified |Implicitly-unwrapped optional, e.g., NSDate! |It is unknown whether the value can be nil (very rare)|

Particularly in Objective-C APIs, many pointers tend to be nonnull. Therefore, Objective-C provides “audited” regions (via a new #pragma) that assume that unannotated pointers are nonnull. For example, the following example is equivalent to the first example, but uses audited regions to simplify the presentation:

#pragma clang assume_nonnull begin
// ...
-(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString*)identifier;
-(nullable UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath)indexPath;
@property (nonatomic, readwrite, retain, nullable) UIView *backgroundView; 
// ...
#pragma clang assume_nonnull end 

For consistency, we recommend using audited regions in all Objective-C headers that describe the nullability of their APIs, and to avoid null_unspecified except as a transitional tool while introducing nullability into existing headers. Adding nullability annotations to Objective-C APIs does not affect backward compatibility or the way in which the compiler generates code. For example, nonnull pointers can still end up being nil in some cases, such as when messaging a nil receiver. However, nullability annotations—in addition to improving the experience in Swift—provide new warnings in Objective-C if, for example, a nil argument is passed to a nonnull parameter, making Objective-C APIs more expressive and easier to use correctly. (18868820) • Objective-C APIs can now express the nullability of properties whose setters allow nil (to “reset” the value to some default) but whose getters never produce nil (because they provide some default instead) using the null_resettable property attribute. One such property is UIView’s tintColor, which substitutes a default system tint color when no tint color has been specified. (19051334) For example:

@property (nonatomic, retain, null_resettable) UIColor *tintColor;

is imported into Swift as:

var tintColor: UIColor!

Parameters of C pointer type or block pointer type can be annotated with the new noescape attribute to indicate that pointer argument won’t “escape” the function or method it is being passed to. (19389222) In such cases, it’s safe to (for example) pass the address of a local variable. noescape block pointer parameters will be imported into Swift as @noescape parameters:

void executeImmediately(__attribute__((noescape)) void (^callback)(void);

is imported into Swift as:

func executeImmediately(@noescape callback: () -> Void)
@xxx50236
Copy link

xxx50236 commented Dec 1, 2016

Does objective-c has attribute attribute((escape))?

@ddlsmurf
Copy link

I don't think that would be useful, since compiling as if it could escape would be enough to work in either case safely, just less performant. Am I missing a use-case for an escape attribute ?

@vitonzhangtt
Copy link

Does objective-c has attribute attribute((escape))?

Look at Attributes in Clang. There is not a __attribute__ for escape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment