Jody Heavener Jody Heavener - 5 months ago 25
Objective-C Question

How does this #define work in Swift?

I am new to iOS and am trying to tackle learning Swift (and a bit of Objective C) by converting a library I found to the former. So far I'm doing alright, but am having trouble understanding one part; how this

#define
is supposed to work:

#define RunSafeBlock(block, ...) block ? block(__VA_ARGS__) : nil


Here it is with more context:

#import <AFNetworking.h>

// How would I write this in Swift?
#define RunSafeBlock(block, ...) block ? block(__VA_ARGS__) : nil

@interface Client ()
@end

@implementation Client
- (void)requestWithBodyBlock:(void (^)(id<AFMultipartFormData> formData))bodyBlock completion:(ClientRequestCompletion)completion {
[self validateAccessToken:^(NSError *error) {
if (error) {
// What does RunSafeBlock do?
RunSafeBlock(completion, nil, error);
return;
}

// ...
}];
}
@end


The
AFNetworking
parts are not really relevant, but in this example we're performing a request and validating an access token. If
validateAccessToken
returns an error, we pass everything to
RunSafeBlock
and exit out. Here we are in Swift:

import AFNetworking

// #define RunSafeBlock(block, ...) block ? block(__VA_ARGS__) : nil

class Client {
func requestWithBodyBlock(bodyBlock: (formData: AFMultipartFormData) -> Void, completion: ClientRequestCompletion) {
self.validateAccessToken({(error: NSError) -> Void in
if error != nil {
// RunSafeBlock(completion, nil, error)
return
}

// ...
})
}
}


I would really appreciate some guidance. Thanks in advance!

Answer

This macro is doing a null-check.

In Swift, unless you declare a variable as Optional, it cannot be null, so you do not have to do this check in Swift (and if it was Optional, you'd use optional unwrapping).

So just go ahead and call the completion.

(It seems the same reasoning would also apply to error. Don't you get a compile error there?)

(Also consider using the Swift version of AlamoFire).

Comments