在Swift中将闭包存储为变量

158
在 Objective-C 中,你可以定义块的输入和输出,存储方法中传入的其中一个块,然后在以后使用该块:
// 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);
            });
     ...
}

所以我正在尝试用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()
}

编译器不喜欢completionHandler的声明。虽然我不怪它,但是我该如何在Swift中定义一个可以设置和后续使用的闭包呢?


1
当你编译时,你遇到了什么错误? - TheLazyChap
8个回答

370
编译器有投诉。
var completionHandler: (Float)->Void = {}

因为右侧不是具有适当签名的闭包,即一个带有浮点参数的闭包。以下代码将会给完成处理程序分配一个“什么也不做”的闭包:

var completionHandler: (Float)->Void = {
    (arg: Float) -> Void in
}

这可以缩短为

var completionHandler: (Float)->Void = { arg in }

由于自动类型推断,这可能是您想要的。

但是,您可能想要的是将完成处理程序初始化为nil,就像Objective-C实例变量初始化为nil一样。 在Swift中,可以使用可选项来实现:

var completionHandler: ((Float)->Void)?

现在这个属性会自动初始化为 nil("没有值")。 在Swift中,你可以使用可选绑定来检查完成处理程序是否有值。

if let handler = completionHandler {
    handler(result)
}

或者可选链:

completionHandler?(result)

1
在Swift中,这可以通过隐式解包可选项或显式解包(即常规)可选项来实现。 - newacct
1
使用 ((Float)->Void)!((Float)->Void)? 有什么不同吗?使用 ? 声明未初始化的可选项默认为 nil,不是吗? - Suragch

48

Objective-C

@interface PopupView : UIView
@property (nonatomic, copy) void (^onHideComplete)();
@end

@interface PopupView ()

...

- (IBAction)hideButtonDidTouch:(id sender) {
    // Do something
    ...
    // Callback
    if (onHideComplete) onHideComplete ();
}

@end

PopupView * popupView = [[PopupView alloc] init]
popupView.onHideComplete = ^() {
    ...
}

Swift

class PopupView: UIView {
    var onHideComplete: (() -> Void)?

    @IBAction func hideButtonDidTouch(sender: AnyObject) {
        // Do something
        ....
        // Callback
        if let callback = self.onHideComplete {
            callback ()
        }
    }
}

var popupView = PopupView ()
popupView.onHideComplete = {
    () -> Void in 
    ...
}

1
但是内存管理是否自动处理正确呢?因为在Obj-C中,您指定该属性为“copy”,但是Swift似乎没有这个选项,而是定义为“strong”,或者它确实有这个选项吗? - Paulius Vindzigelskis
为什么需要复制它? - Dmitry

14

我提供了一个例子,不确定这是否是你想要的。

var completionHandler: (_ value: Float) -> ()

func printFloat(value: Float) {
    print(value)
}

completionHandler = printFloat

completionHandler(5)

代码使用声明的completionHandler变量简单地打印出数字5。


8

闭包可以声明为以下的typealias

typealias Completion = (Bool, Any, Error) -> Void

如果您想在代码的任何地方使用in函数,可以像普通变量一样编写。
func xyz(with param1: String, completion: Completion) {
}

7
在Swift 4和5中,我创建了一个包含两个参数字典和布尔值的闭包变量。
 var completionHandler:([String:Any], Bool)->Void = { dict, success  in
    if success {
      print(dict)
    }
  }

调用闭包变量
self.completionHandler(["name":"Gurjinder singh"],true)

4

这也可以运行:

var exeBlk = {
    () -> Void in
}
exeBlk = {
    //do something
}
//instead of nil:
exeBlk = {}

1

如果根据您的需求,接受的答案还需要补充。您也可以像这样实现它:

var parseCompletion: (() ->Void)!

后来在某个函数中对其进行了赋值

func someHavyFunc(completion: @escaping () -> Void){
    self.parseCompletion = completion
}

并在某些第二个函数中使用它

func someSecondFunc(){
    if let completion = self.parseCompletion {
        completion()
    }
}

请注意,此处 @escaping 参数是必需的。

0
对我来说,以下内容是有效的:
var completionHandler:((Float)->Void)!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接