Skip to content

Instantly share code, notes, and snippets.

Last active Jan 19, 2021
What would you like to do?
A macro to convert nullable references to nonnull references while triggering an assert if the expression is actually true. Think of this as unsafe unwrap for Objective-C.
void Log(NSString *foo) {
NSLog(@"%@", foo);
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSDictionary *stuff = @{
@"a": @"Test"
// This will trigger a warning in Xcode 7 if
// `-Wnullable-to-nonnull-conversion` is enabled:
// Implicit conversion from nullable pointer 'id _Nullable' to non-
// nullable pointer type 'NSString * _Nonnull'.
/// This will not trigger a warning.
/// This will trigger the assert.
return 0;
#if __has_feature(objc_generics)
/// An unimplemented class used to trick the compiler, since a cast along the
/// lines of
/// (__nonnull __typeof(bla))bla;
/// is not possible.
@interface RBBBox<__covariant Type>
- (nonnull Type)asNonNull;
/// This macro allows us to cast a nullable reference to a non-nullable
/// reference that would otherwise trigger a warning if
/// `-Wnullable-to-nonnull-conversion` is enabled.
#define RBBNotNil(V) \
({ \
NSCAssert(V, @"Expected '%@' not to be nil.", @#V); \
RBBBox<__typeof(V)> *type; \
(__typeof(type.asNonNull))V; \
/// If generics are unavailable, so is `-Wnullable-to-nonnull-conversion`.
#define RBBNotNil(V) \
({ \
NSCAssert(V, @"Expected '%@' not to be nil.", @#V); \
V; \
Copy link

hborders commented Sep 8, 2017

This is really great!

I ran into some static analyzer warnings with in when archiving. I outlined details in a stack overflow answer.

// We purposefully don't have a matching @implementation.
// We don't want +asNonnull to ever actually be called
// because that will add a lot of overhead to every RBBNotNil
// and we want RBBNotNil to be very cheap.
// If there is no @implementation, then if the +asNonnull is
// actually called, we'll get a linker error complaining about
// the lack of @implementation.
@interface RBBBox <__covariant Type>

// This as a class method so you don't need to
// declare an unused lvalue just for a __typeof
+ (Type _Nonnull)asNonnull;


 * @define RBBNotNil(V)
 * Converts an Objective-C object expression from _Nullable to _Nonnull. 
 * Crashes if it receives a nil! We must crash or else we'll receive
 * static analyzer warnings when archiving. I think in Release mode,
 * the compiler ignores the _Nonnull cast.
 * @param V a _Nullable Objective-C object expression
#define RBBNotNil(V) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wgnu-statement-expression\"") \
({ \
__typeof__(V) __nullableV = V; \
NSCAssert(__nullableV, @"Expected '%@' not to be nil.", @#V); \
if (!__nullableV) { \
    abort(); \
} \
(__typeof([RBBNotNil<__typeof(V)> asNonnull]))__nullableV; \
}) \
_Pragma("clang diagnostic pop")

Copy link

CodingMarkus commented Oct 23, 2020

#define assumeNotNull(_value) \
    ({ if (!_value) abort(); __auto_type const _temp = _value; _temp; })

use as

if (parameters) {
    [obj processParameters:assumeNotNull(parameters)];

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