Memorizza una chiusura come variabile in Swift


140

In Objective-C, puoi definire l'input e l'output di un blocco, archiviare uno di quei blocchi passati a un metodo, quindi utilizzare quel blocco in un secondo momento:

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

Quindi sto provando a fare l'equivalente 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()
}

Al compilatore non piace quella dichiarazione di completamentoHandler. Non che lo biasimo, ma come definisco una chiusura che può essere impostata e utilizzata in seguito in Swift?


1
Che errore ricevi quando compili?
TheLazyChap,

Risposte:


335

Il compilatore si lamenta

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

perché il lato destro non è una chiusura della firma appropriata, vale a dire una chiusura che assume un argomento float. Quanto segue assegnerebbe una chiusura "non fare nulla" al gestore del completamento:

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

e questo può essere abbreviato in

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

a causa dell'inferenza di tipo automatica.

Ma quello che probabilmente vuoi è che il gestore di completamento sia inizializzato nil nello stesso modo in cui una variabile di istanza Objective-C è inizializzata nil. In Swift questo può essere realizzato con un optional :

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

Ora la proprietà viene automaticamente inizializzata su nil("nessun valore"). In Swift useresti un'associazione opzionale per verificare se il gestore di completamento ha un valore

if let handler = completionHandler {
    handler(result)
}

o concatenamento opzionale:

completionHandler?(result)

1
"In Swift questo può essere realizzato con un facoltativo
involontariamente non imballato

1
L'utilizzo è ((Float)->Void)!diverso da ((Float)->Void)?? La dichiarazione di un facoltativo non inizializzato con ?impostazione predefinita è nilgià?
Suragch,

43

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

veloce

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
Ma la gestione della memoria è gestita automaticamente in modo corretto? Perché in Obj-C specifichi che la proprietà è "copia", ma swift sembra non avere quell'opzione ed è invece definito come "forte" o no?
Paulius Vindzigelskis,

Perché è necessario copiarlo?
Dmitry,

9

Ho fornito un esempio non sicuro se questo è ciò che stai cercando.

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

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

completionHandler = printFloat

completionHandler(5)

Stampa semplicemente 5 usando la completionHandlervariabile dichiarata.


7

In Swift 4 e 5 . Ho creato una variabile di chiusura contenente due parametri del dizionario e bool.

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

Chiamando la variabile di chiusura

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

5

Le chiusure possono essere dichiarate come typealiasdi seguito

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

Se vuoi usare la tua funzione ovunque nel codice; puoi scrivere come una normale variabile

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

3

Funziona anche questo:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.