Lưu trữ một bao đóng như một biến trong Swift


140

Trong Objective-C, bạn có thể xác định đầu vào và đầu ra của một khối, lưu trữ một trong những khối được truyền vào một phương thức, sau đó sử dụng khối đó sau:

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

Vì vậy, tôi đang cố gắng làm điều tương tự trong 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()
}

Trình biên dịch không giống như tuyên bố của xongHandler. Không phải tôi đổ lỗi cho nó, nhưng, làm cách nào để xác định một bao đóng có thể được thiết lập và sử dụng sau này trong Swift?


1
Lỗi gì khi bạn biên dịch?
TheLazyChap

Câu trả lời:


334

Trình biên dịch phàn nàn về

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

bởi vì phía bên tay phải không phải là một chữ ký thích hợp, tức là một bao đóng lấy một đối số float. Sau đây sẽ chỉ định đóng "không làm gì" cho trình xử lý hoàn thành:

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

và điều này có thể được rút ngắn thành

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

do suy luận kiểu tự động.

Nhưng những gì bạn có thể muốn là trình xử lý hoàn thành được khởi tạo nil theo cùng một cách mà một biến đối tượng Objective-C được khởi tạo nil. Trong Swift, điều này có thể được nhận ra với một tùy chọn :

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

Bây giờ thuộc tính được tự động khởi tạo thành nil("không có giá trị"). Trong Swift, bạn sẽ sử dụng ràng buộc tùy chọn để kiểm tra trình xử lý hoàn thành có giá trị

if let handler = completionHandler {
    handler(result)
}

hoặc chuỗi tùy chọn:

completionHandler?(result)

1
"Trong Swift, điều này có thể được nhận ra với một tùy chọn hoàn toàn không được bao bọc" Hoặc một "tùy chọn rõ ràng chưa được mở" (tức là thường xuyên) tùy chọn
newacct

1
Là sử dụng ((Float)->Void)!bất kỳ khác nhau hơn ((Float)->Void)?? Không khai báo một tùy chọn chưa được khởi tạo với ?mặc định nilđã có?
Suragch

43

Mục tiêu-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 = ^() {
    ...
}

Nhanh

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
Nhưng quản lý bộ nhớ được xử lý tự động chính xác? Bởi vì trong Obj-C Bạn chỉ định thuộc tính đó là "bản sao", nhưng swift dường như không có tùy chọn đó và được định nghĩa là "mạnh" thay vào đó, hay nó?
Paulius Vindzigelskis

Tại sao cần phải sao chép nó?
Dmitry

9

Tôi đã cung cấp một ví dụ không chắc chắn nếu đây là những gì bạn đang theo đuổi.

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

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

completionHandler = printFloat

completionHandler(5)

Nó chỉ đơn giản là in 5 bằng cách sử dụng completionHandlerbiến được khai báo.


7

Trong Swift 4 và 5 . Tôi đã tạo một biến đóng có chứa hai từ điển tham số và bool.

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

Gọi biến đóng

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

5

Đóng cửa có thể được khai báo typealiasnhư dưới đây

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

Nếu bạn muốn sử dụng chức năng của mình ở bất cứ đâu trong mã; bạn có thể viết như biến bình thường

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

3

Điều này cũng hoạt động:

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

-1

Đối với tôi sau đây đã làm việc:

var completionHandler:((Float)->Void)!
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.