Menyimpan penutupan sebagai variabel dalam Swift

140

Di Objective-C, Anda bisa menentukan input dan output blok, simpan salah satu blok yang diteruskan ke metode, lalu gunakan blok itu nanti:

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

Jadi saya mencoba melakukan equivilant di 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()
}

Kompiler tidak suka pernyataan penyelesaian Handler. Bukannya saya menyalahkannya, tetapi, bagaimana saya mendefinisikan penutupan yang dapat diatur dan digunakan nanti di Swift?

Jay Dub
sumber
1
Kesalahan apa yang Anda dapatkan, saat Anda kompilasi?
TheLazyChap

Jawaban:

335

Kompiler mengeluh

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

karena sisi kanan bukanlah penutupan dari tanda tangan yang sesuai, yaitu penutupan yang mengambil argumen float. Yang berikut ini akan memberikan penutupan "jangan lakukan apa pun" pada penangan penyelesaian:

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

dan ini dapat disingkat menjadi

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

karena inferensi tipe otomatis.

Tapi apa yang Anda inginkan adalah bahwa handler penyelesaian diinisialisasi dengan nil cara yang sama bahwa variabel instance Objective-C diinisialisasi ke nil. Dalam Swift ini dapat diwujudkan dengan opsional :

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

Sekarang properti secara otomatis diinisialisasi ke nil("tidak ada nilai"). Di Swift Anda akan menggunakan penjilidan opsional untuk memeriksa penangan penyelesaian memiliki nilai

if let handler = completionHandler {
    handler(result)
}

atau rantai opsional:

completionHandler?(result)
Martin R
sumber
1
"Di Swift, ini dapat diwujudkan dengan opsional" Atau "secara eksplisit tidak terbuka" (yaitu reguler) opsional
newacct
1
Apakah menggunakan ((Float)->Void)!berbeda dari ((Float)->Void)?? Bukankah mendeklarasikan opsional yang belum diinisialisasi dengan ?standar nilsudah?
Suragch
43

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

Cepat

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ạ
sumber
1
Tetapi apakah manajemen memori ditangani secara otomatis benar? Karena di Obj-C Anda menentukan properti itu untuk menjadi "copy", tetapi swift tampaknya tidak memiliki opsi itu dan didefinisikan sebagai "kuat", atau bukan?
Paulius Vindzigelskis
Mengapa harus menyalinnya?
Dmitry
9

Saya telah memberikan contoh yang tidak yakin apakah ini yang Anda cari.

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

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

completionHandler = printFloat

completionHandler(5)

Ini hanya mencetak 5 menggunakan completionHandlervariabel yang dideklarasikan.

TheLazyChap
sumber
7

Dalam Swift 4 dan 5 . Saya membuat variabel penutupan yang berisi dua kamus parameter dan bool.

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

Memanggil variabel penutupan

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

Penutupan dapat dinyatakan typealiassebagai berikut

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

Jika Anda ingin menggunakan fungsi Anda di mana saja dalam kode; Anda dapat menulis seperti variabel normal

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

Ini juga berfungsi:

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

Bagi saya berikut ini berfungsi:

var completionHandler:((Float)->Void)!
letsdev-cwack
sumber