web-dev-qa-db-fra.com

Stocker une fermeture en tant que variable dans Swift

En Objective-C, vous pouvez définir l'entrée et la sortie d'un bloc, stocker l'un de ces blocs transmis à une méthode, puis utiliser ce bloc ultérieurement:

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

Alors j'essaie de faire l'équivalent dans 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()
}

Le compilateur n'aime pas cette déclaration de completionHandler. Non pas que je le blâme, mais comment définir une fermeture pouvant être définie et utilisée ultérieurement dans Swift?

128
Jay Dub

Le compilateur se plaint

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

parce que le membre de droite n'est pas une fermeture de la signature appropriée, c’est-à-dire une fermeture prenant un argument float. Les éléments suivants attribueraient une fermeture "ne rien faire" au gestionnaire d'achèvement:

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

et cela peut être réduit à

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

en raison de l'inférence de type automatique.

Mais ce que vous voulez probablement, c'est que le gestionnaire d'achèvement soit initialisé à nil de la même manière qu'une variable d'instance Objective-C est initialisée à nil. Dans Swift ceci peut être réalisé avec un optionnel :

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

Maintenant, la propriété est automatiquement initialisée à nil ("pas de valeur"). Dans Swift, vous utiliseriez une liaison facultative pour vérifier si le gestionnaire d'achèvement a une valeur

if let handler = completionHandler {
    handler(result)
}

ou chaînage optionnel:

completionHandler?(result)
309
Martin R

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

rapide

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 
    ...
}
37
Phước Hải Tạ

J'ai fourni un exemple pas sûr si c'est ce que vous cherchez.

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

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

completionHandler = printFloat

completionHandler(value: 5)

Il imprime simplement 5 en utilisant la variable completionHandler déclarée.

7
TheLazyChap

Dans Swift 4 et 5. J'ai créé une variable de fermeture contenant deux dictionnaire de paramètres et bool.

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

Appel de la variable de fermeture

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

Les fermetures peuvent être déclarées comme typealias comme ci-dessous

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

Si vous souhaitez utiliser dans votre fonction n'importe où dans le code; vous pouvez écrire comme variable normale

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

Cela fonctionne aussi:

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