In Objective-C, you can define a block's input and output, store one of those blocks that's passed in to a method, then use that block later:
// in .h
typedef void (^APLCalibrationProgressHandler)(float percentComplete);
typedef void (^APLCalibrationCompletionHandler)(NSInteger measuredPower, NSError *error);
// in .m
@property (strong) APLCalibrationProgressHandler progressHandler;
@property (strong) APLCalibrationCompletionHandler completionHandler;
- (id)initWithRegion:(CLBeaconRegion *)region completionHandler:(APLCalibrationCompletionHandler)handler
{
self = [super init];
if(self)
{
...
_completionHandler = [handler copy];
..
}
return self;
}
- (void)performCalibrationWithProgressHandler:(APLCalibrationProgressHandler)handler
{
...
self.progressHandler = [handler copy];
...
dispatch_async(dispatch_get_main_queue(), ^{
_completionHandler(0, error);
});
...
}
So I'm trying to do the equivilant in Swift:
var completionHandler:(Float)->Void={}
init() {
locationManager = CLLocationManager()
region = CLBeaconRegion()
timer = NSTimer()
}
convenience init(region: CLBeaconRegion, handler:((Float)->Void)) {
self.init()
locationManager.delegate = self
self.region = region
completionHandler = handler
rangedBeacons = NSMutableArray()
}
The compiler doesn't like that declaration of completionHandler. Not that I blame it, but, how do I define a closure that can be set and used later in Swift?
The compiler complains on
var completionHandler: (Float)->Void = {}
because the right-hand side is not a closure of the appropriate signature, i.e. a closure taking a float argument. The following would assign a "do nothing" closure to the completion handler:
var completionHandler: (Float)->Void = {
(arg: Float) -> Void in
}
and this can be shortened to
var completionHandler: (Float)->Void = { arg in }
due to the automatic type inference.
But what you probably want is that the completion handler is initialized to nil
in the same way that an Objective-C instance variable is inititialized to nil
. In Swift
this can be realized with an optional:
var completionHandler: ((Float)->Void)?
Now the property is automatically initialized to nil
("no value").
In Swift you would use optional binding to check of a the
completion handler has a value
if let handler = completionHandler {
handler(result)
}
or optional chaining:
completionHandler?(result)