Зберігайте закриття як змінну в Swift


140

У 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);
            });
     ...
}

Тому я намагаюся зробити еквівалент у Свіфті:

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()
}

Компілятору не подобається ця заява про завершенняHandler. Я не в тому, що я звинувачую це, але як я можу визначити закриття, яке можна встановити та використати пізніше у Swift?


1
Яку помилку ви отримуєте під час компіляції?
TheLazyChap

Відповіді:


335

Укладач скаржиться на

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

тому що правий бік не є закриттям відповідного підпису, тобто закриттям з аргументом float. Далі буде призначено закриття "не робити нічого" оброблювачеві завершення:

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?
Сурагч

43

Ціль-С

@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 = ^() {
    ...
}

Швидкий

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 ви вказуєте, що властивість "копіювати", але, здається, що швидкий не має такої опції і натомість визначається як "сильний", чи це?
Паулій Віндігельскіс

Чому його потрібно копіювати?
Дмитро

9

Я наводив приклад, не впевнений, чи це ти, що ти хочеш

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

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

completionHandler = printFloat

completionHandler(5)

Він просто друкує 5 за допомогою completionHandlerоголошеної змінної.


7

У Swift 4 і 5 . Я створив змінну закриття, що містить два словника параметрів і bool.

 var completionHandler:([String:Any], Bool)->Void = { dict, success  in
    if success {
      print(dict)
    }
  }

Виклик змінної закриття

self.completionHandler(["name":"Gurjinder singh"],true)

5

Закриття можна оголосити як typealias як наведено нижче

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

Якщо ви хочете використовувати у своїй функції будь-де в коді; ви можете писати як звичайна змінна

func xyz(with param1: String, completion: Completion) {
}


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.