Speichern Sie einen Abschluss als Variable in Swift

140

In Objective-C können Sie die Ein- und Ausgabe eines Blocks definieren, einen der Blöcke speichern, die an eine Methode übergeben wurden, und diesen Block später verwenden:

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

Also versuche ich, in Swift das Gleiche zu tun:

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

Der Compiler mag diese Completion-DeklarationHandler nicht. Nicht dass ich es beschuldige, aber wie definiere ich einen Abschluss, der später in Swift festgelegt und verwendet werden kann?

Jay Dub
quelle
1
Welchen Fehler erhalten Sie beim Kompilieren?
TheLazyChap

Antworten:

334

Der Compiler beschwert sich weiter

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

weil die rechte Seite kein Abschluss der entsprechenden Signatur ist, dh ein Abschluss, der ein Float-Argument enthält. Das Folgende würde dem Abschluss-Handler einen Abschluss "Nichts tun" zuweisen:

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

und dies kann verkürzt werden auf

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

aufgrund der automatischen Typinferenz.

Aber was wollen Sie wahrscheinlich ist , dass der Abschluss - Handler initialisiert wird nil auf die gleiche Art und Weise , dass eine Objective-C Instanzvariable ist inititialized zu nil. In Swift kann dies mit einem optionalen realisiert werden :

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

Jetzt wird die Eigenschaft automatisch auf nil("kein Wert") initialisiert . In Swift würden Sie die optionale Bindung verwenden, um zu überprüfen, ob der Completion-Handler einen Wert hat

if let handler = completionHandler {
    handler(result)
}

oder optionale Verkettung:

completionHandler?(result)
Martin R.
quelle
1
"In Swift kann dies mit einem implizit ausgepackten optionalen" oder einem "explizit ausgepackten" (dh regulären) optionalen
newacct
1
Ist die Verwendung ((Float)->Void)!anders als ((Float)->Void)?? Wird eine nicht initialisierte Option nicht ?standardmäßig mit nilbereits deklariert ?
Suragch
43

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

Schnell

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 
    ...
}
Phước Hải Tạ
quelle
1
Aber ist die Speicherverwaltung automatisch korrekt? Weil Sie in Obj-C angeben, dass diese Eigenschaft "kopieren" soll, aber Swift diese Option anscheinend nicht hat und stattdessen als "stark" definiert ist, oder?
Paulius Vindzigelskis
Warum muss es kopiert werden?
Dmitry
9

Ich habe ein Beispiel angegeben, bei dem ich nicht sicher bin, ob Sie danach suchen.

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

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

completionHandler = printFloat

completionHandler(5)

Es wird einfach 5 mit der completionHandlerdeklarierten Variablen gedruckt .

TheLazyChap
quelle
7

In Swift 4 und 5 . Ich habe eine Abschlussvariable erstellt, die zwei Parameter Dictionary und Bool enthält.

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

Aufruf der Abschlussvariablen

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

Schließungen können wie folgt deklariert typealiaswerden

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

Wenn Sie in Ihrer Funktion irgendwo im Code verwenden möchten; Sie können wie eine normale Variable schreiben

func xyz(with param1: String, completion: Completion) {
}
Saurabh Kumar
quelle
3

Das funktioniert auch:

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

Für mich hat folgendes funktioniert:

var completionHandler:((Float)->Void)!
letdev-cwack
quelle