เก็บการปิดเป็นตัวแปรใน Swift


141

ใน 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 = {}

เพราะด้านขวาไม่ใช่การปิดลายเซ็นที่เหมาะสมเช่นการปิดรับอาร์กิวเมนต์ลอย ต่อไปนี้จะกำหนดการปิด "ไม่ทำอะไรเลย" ให้กับตัวจัดการความสมบูรณ์:

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หรือไม่?
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 = ^() {
    ...
}

รวดเร็ว

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 คุณระบุว่าคุณสมบัตินั้นเป็น "copy" แต่ swift ดูเหมือนจะไม่มีตัวเลือกนั้นและถูกกำหนดเป็น "strong" แทนหรือไม่
Paulius Vindzigelskis

เหตุใดจึงต้องคัดลอก
มิทรี

9

ฉันให้ตัวอย่างไม่แน่ใจว่านี่คือสิ่งที่คุณต้องการ

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

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

completionHandler = printFloat

completionHandler(5)

มันพิมพ์ 5 โดยใช้completionHandlerตัวแปรที่ประกาศ


7

ในสวิฟท์ที่ 4 และ 5 ฉันสร้างตัวแปรการปิดประกอบด้วยพจนานุกรมสองพารามิเตอร์และบูล

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


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.