Swift tùy chọn thoát tham số đóng


162

Được:

typealias Action = () -> ()

var action: Action = { }

func doStuff(stuff: String, completion: @escaping Action) {
    print(stuff)
    action = completion
    completion()
}

func doStuffAgain() {
    print("again")
    action()
}

doStuff(stuff: "do stuff") { 
    print("swift 3!")
}

doStuffAgain()

Có cách nào để tạo completiontham số (và action) của loại Action?và cũng giữ @escapingkhông?

Thay đổi loại cho lỗi sau:

Thuộc tính @escaping chỉ áp dụng cho các loại chức năng

Xóa @escapingthuộc tính, mã biên dịch và chạy, nhưng dường như không chính xác vì bao completionđóng đang thoát khỏi phạm vi của hàm.


21
"Loại bỏ các @escapingthuộc tính, các biên dịch mã và chạy" - Đó là bởi vì, như mô tả trong SR-2444 , Action?là, theo mặc định, thoát. Vì vậy, loại bỏ @escapingkhi sử dụng đóng tùy chọn hoàn thành những gì bạn cần.
Rob


loại đóng cửa bí danh đang thoát
Masih

Đây là một bài viết tuyệt vời của Ole Begemann mô tả lý do tại sao nó xảy ra và một số cách giải quyết nếu bạn muốn các tham số tùy chọn là @noescape.
Ý thức

Câu trả lời:


122

Có một báo cáo SR-2552@escaping không nhận dạng bí danh loại chức năng. đó là lý do tại sao lỗi @escaping attribute only applies to function types. bạn có thể giải quyết bằng cách mở rộng loại hàm trong chữ ký hàm:

typealias Action = () -> ()

var action: Action? = { }

func doStuff(stuff: String, completion: (@escaping ()->())?) {
    print(stuff)
    action = completion
    completion?()
}

func doStuffAgain() {
    print("again")
    action?()
}

doStuff(stuff: "do stuff") {
    print("swift 3!")
}

doStuffAgain()

EDIT 1 ::

Tôi thực sự đã ở phiên bản xcode 8 beta mà lỗi SR-2552 chưa được khắc phục. sửa lỗi đó, giới thiệu một lỗi mới (lỗi mà bạn gặp phải) vẫn đang mở. xem SR-2444 .

Cách giải quyết @Michael Ilseman được chỉ ra là một giải pháp tạm thời là loại bỏ @escapingthuộc tính khỏi loại chức năng tùy chọn, giữ cho chức năng là thoát .

func doStuff(stuff: String, completion: Action?) {...}

EDIT 2 ::

Các SR-2444 đã được đóng trong đó nêu rõ ràng rằng việc đóng cửa trong các thông số vị trí không thoát và cần họ được đánh dấu bằng @escapingđể làm cho họ thoát, nhưng các thông số tùy chọn được ngầm thoát, vì ((Int)->())?là một từ đồng nghĩa của Optional<(Int)->()>, đóng cửa không bắt buộc được thoát.


5
Hiện đang nhận được@escaping may only be applied to parameters of function type func doStuff(stuff: String, completion: (@escaping ()->())?) {
Lescai Ionel

1
a temporary solution is remove the @escaping attribute from optional function type, that keep the function as escaping. Bạn có thể giải thích điều này hơn nữa? Ngữ nghĩa mặc định trong swift 3 là không thoát. Mặc dù nó biên dịch mà không có @escaping nhưng tôi sợ nó sẽ gây ra vấn đề bằng cách được coi là không thoát. Điều đó có đúng không?
Pat Niemeyer

49
Khi đọc thêm tôi thấy rằng SR-2444 nói rằng tất cả các lần đóng tùy chọn được coi là thoát, đó là một lỗi bổ sung :) Tôi sẽ giả định rằng khi nó được sửa, trình biên dịch sẽ cảnh báo chúng tôi thực hiện thay đổi.
Pat Niemeyer

Có lẽ hơi lạc đề; nhưng làm thế nào để làm việc này @autoclosure? Một người mắc lỗi tương tự ở đó ...
Gee.E

nó hoạt động mà không có @escaping __ func doStuff (thứ: Chuỗi, hoàn thành: (() -> ())?) {
Феннур Мезитов

226

từ: danh sách gửi thư của người dùng swift

Về cơ bản, @escaping chỉ hợp lệ khi đóng ở vị trí tham số chức năng. Quy tắc noescape theo mặc định chỉ áp dụng cho các bao đóng này tại vị trí tham số chức năng, nếu không chúng đang thoát. Các tập hợp, chẳng hạn như enum với các giá trị liên quan (ví dụ: Tùy chọn), bộ dữ liệu, cấu trúc, v.v., nếu chúng có các bao đóng, hãy tuân theo các quy tắc mặc định cho các bao đóng không ở vị trí tham số chức năng, tức là chúng đang thoát.

Vì vậy, tham số chức năng tùy chọn là @escaping theo mặc định.
@noeascape chỉ áp dụng cho tham số chức năng theo mặc định.


7
Tôi nghĩ rằng điều này thêm thông tin quan trọng nhất cho chủ đề, nó nên được chấp nhận câu trả lời.
Damian Dudycz

Câu trả lời có lý do. Làm thế nào có khả năng là điều này có thể thay đổi?
GoldenJoe

2
Điều này có ý nghĩa vì về mặt kỹ thuật nói (()->Void)?cũng giống như bạn nói Optional<()->Void>Optionalđể duy trì quyền sở hữu, nó sẽ chỉ phải chấp nhận các @escapingchức năng. Tôi sẽ thứ ba rằng đây sẽ là câu trả lời được chấp nhận. Cảm ơn bạn.
Dean Kelly

22

Tôi gặp phải một vấn đề tương tự vì trộn @escapingvà không - @escapingrất khó hiểu, đặc biệt là nếu bạn cần vượt qua các khoảng cách xung quanh.

Cuối cùng tôi đã gán một giá trị mặc định không op cho tham số đóng thông qua = { _ in }, điều mà tôi nghĩ có ý nghĩa hơn:

func doStuff(stuff: String = "do stuff",
        completion: @escaping (_ some: String) -> Void = { _ in }) {
     completion(stuff)
}

doStuff(stuff: "bla") {
    stuff in
    print(stuff)
}

doStuff() {
    stuff in
    print(stuff)
}

Điều này là sạch sẽ và đẹp trong thực hiện.
Fred Faust

2
Điều gì xảy ra nếu tôi muốn kiểm tra nếu khối này không / trống?
Vyachaslav Gerchicov

2
Bummer, điều này không làm việc cho một phương thức giao thức. "Đối số mặc định không được phép trong phương thức giao thức" (Xcode 8.3.2).
Mike Cheesne

17

Tôi đã làm cho nó hoạt động trong Swift 3 mà không có bất kỳ cảnh báo nào theo cách này:

func doStuff(stuff: String, completion: (()->())? ) {
    print(stuff)
    action = completion
    completion?()
}

4

Điều quan trọng cần hiểu trong ví dụ là nếu bạn thay đổi Actionthành Action?bao đóng đang thoát. Vì vậy, hãy làm những gì bạn đề xuất:

typealias Action = () -> ()

var action: Action? = { }

func doStuff(stuff: String, completion: Action?) {
    print(stuff)
    action = completion
    completion?()
}

Được rồi, bây giờ chúng tôi sẽ gọi doStuff:

class ViewController: UIViewController {
    var prop = ""
    override func viewDidLoad() {
        super.viewDidLoad()
        doStuff(stuff: "do stuff") {
            print("swift 3!")
            print(prop) // error: Reference to property 'prop' in closure 
                        // requires explicit 'self.' to make capture semantics explicit
        }
    }
}

Vâng, yêu cầu đó chỉ phát sinh để thoát khỏi sự đóng cửa. Vì vậy, việc đóng cửa đang thoát ra. Đó là lý do tại sao bạn không đánh dấu nó thoát - nó đã thoát.

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.