SwiftyAs

March 25th, 2015 · · objc, swift, open source, development

Let me introduce: SwiftyAs. It's a tiny little library to provide sort of the same functionality as as? from Swift in Objective-C. Let me explain...

The gist

In Swift, you can use the as? operator to safely cast a variable to another type (albeit Optional). If the actual type at runtime doesn't match, Swift turns it into a nil, and otherwise you just get the variable as an optional. Pretty handy:

let source: AnyObject = NSDictionary()

let array: source as? NSArray
// array = nil
let dict: source as? NSDictionary
// dict = source

Now with SwiftyAs you can do kind of the same in Objective-C:

NSObject *source = [NSDictionary new];

NSArray* array = source.as(NSArray);
// array = nil
NSDictionary* dict = source.as(NSDictionary);
// dict = source

There's nothing new under the sun here, and you can do exactly the same with an if statement and a isKindOfClass: check:

NSObject *source = [NSDictionary new];
NSArray *array = nil;
if ([source isKindOfObject:[NSArray Class]]) {
    array = (NSArray*)source;
}

but that's more cumbersome and I think the SwiftyAs way is a lot more readable.

Innards

So how does this work?

SwiftyAs introduces a category on NSObject, providing a readonly block property taking a Class and returning an id. The class represents the desired type.

@property (nonatomic, strong, readonly) id(^as)(Class ofClass);

The implementation does nothing more than aforementioned isKindOfClass: check, but in a block (since that is what the property represents):

- (id (^)(__unsafe_unretained Class))as {
    __weak typeof(self) welf = self;
    return ^(Class ofClass) {
        return [welf isKindOfClass:ofClass] ? welf : nil;
    };
}

We need to do some trickery with passing self as weak, because there's no assurance (or obligation) that the as property block is going to used right away. You could take the block, store it somewhere else and call it later if you wanted. Although that's not the intended and common case use, we do have to cater for it.

And so we reference self as weak inside the block, so that any lingering as references won't cause the parent object to remain retained. And if the object's gone, we just return nil anyway which is kinda the intended behavior.

Tiny but easy

So it's a really tiny library (if you even could call it that?). It's just category on NSObject providing the as "keyword" in Objective-C. You can't use it on objects of type id because that's how categories work in Objective-C, but hey, I can live with that.

So there. Available as a CocoaPod, of course:

pod 'SwiftyAs', '~> 1.0'

Enjoy!