Pertanyaan Memperbarui penutupan ke Swift 3 - @escaping


Saya telah memperbarui kode saya ke Xcode 8.0 beta 6 tapi saya terjebak dengan apa yang tampaknya tentang default penutupan non melarikan diri baru. Dalam kode berikut Xcode menyarankan untuk menambahkan @escaping di depan completion: di baris pertama kode di bawah, tetapi itu masih tidak dapat dikompilasi dan berputar-putar. *

(EDIT: Sebenarnya, @caping harus ditambahkan setelah  completion:, seperti saran Xcode. Peringatan mungkin masih muncul tetapi pembersihan dan kompilasi akan menghapusnya.) * Bagaimana seharusnya kode ini ditulis ulang / diperbaiki untuk bekerja di Swift 3 yang diperbarui? Saya sudah melihat di manual baru tapi saya tidak bisa menemukan sampel kode yang tepat.

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}

Bantuan apa pun sangat dihargai!


75
2017-08-21 11:06


asal


Jawaban:


Swift 3: atribut parameter penutupan sekarang diterapkan ke parameter mengetik, dan bukan parameternya sendiri

Sebelum Swift 3, atribut penutupan @autoclosure dan @noescape dulu atribut untuk penutupan parameter, tetapi sekarang atribut ke parameter mengetik; lihat proposal evolusi Swift yang diterima berikut ini:

Pertanyaan spesifik Anda terkait dengan atribut tipe parameter @escaping (untuk mana aturan baru yang sama berlaku), seperti yang dijelaskan dalam proposal evolusi Swift yang diterima untuk membiarkan parameter penutupan menjadi non-escape secara default:

Proposal ini sekarang diimplementasikan pada tahap beta Xcode 8 (lihat rilis catatan untuk Xcode 8 beta 6; dev. login akun diperlukan untuk akses)

Baru di Xcode 8 beta 6 - Swift Compiler: Swift Language

Parameter penutup tidak non-lari secara default, bukan secara eksplisit   dianotasi dengan @noescape. Menggunakan @escaping untuk menunjukkan bahwa a   parameter penutupan dapat melarikan diri. @autoclosure(escaping) sekarang ditulis sebagai    @autoclosure @escaping. Anotasi @noescape dan    @autoclosure(escaping) sudah ditinggalkan. (SE-0103)

...

Baru di Xcode 8 beta - Swift dan Apple LLVM Compiler: Swift Language

Itu @noescape dan @autoclosure atribut sekarang harus ditulis   sebelum jenis parameter, bukan sebelum nama parameter. [SE-0049]

Oleh karena itu, Anda menggunakan non-default @escaping atribut sebagai berikut; diterapkan pada mengetik dari parameter penutupan, daripada parameter itu sendiri

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}

(Termasuk jawaban saya untuk sebuah pertanyaan di komentar upvoted di bawah ini, karena komentar bukan data persisten pada SO)

@Cristi Băluță: "Apa yang melarikan diri? Pernah melihat kata kunci ini   sebelum swift3 auto-conversion ... "

Lihat mis. tautan ke Proposal evolusi SE-0103 di atas (serta teks kutipan dari catatan rilis beta 6): sebelumnya, parameter penutupan melarikan diri secara default (sehingga tidak perlu adanya anotasi eksplisit untuk melarikan diri), tetapi sekarang bukannya non-melarikan diri, secara default. Oleh karena itu penambahan @escaping untuk memberi anotasi secara eksplisit bahwa parameter penutupan dapat keluar (bertentangan dengan perilaku default-nya). Ini juga menjelaskan mengapa @noescapesekarang tidak lagi digunakan (tidak perlu membubuhi keterangan perilaku default).

Untuk menjelaskan apa artinya parameter penutupan melarikan diri, saya kutip Referensi Bahasa - atribut:

"Terapkan atribut ini ke jenis parameter dalam deklarasi metode atau fungsi untuk menunjukkan bahwa nilai parameter dapat disimpan   eksekusi nanti. Ini berarti bahwa nilai tersebut dibolehkan untuk hidup lebih lama   seumur hidup panggilan. "


58
2017-08-21 12:05



@noescape

Dari xcode 8 beta 6 @noescape adalah standarnya. Sebelum itu, @escaping adalah standarnya. Semua yang memperbarui ke swift 3.0 dari versi sebelumnya mungkin menghadapi kesalahan ini.

Anda tidak dapat menyimpan file @noescape penutupan di dalam sebuah variabel. Karena jika Anda dapat menyimpan penutupan di dalam variabel, Anda dapat melakukan penutupan dari mana saja di kode Anda. Tapi @noescape menyatakan bahwa parameter penutupan tidak bisa lepas dari fungsi tubuh.

Ini akan memberikan kesalahan kompiler di Xcode 8

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ️ Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}

Ini akan mengkompilasi ok (secara eksplisit menulis @escaping)

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}

Manfaat dari @noescape:

  • Compiler dapat mengoptimalkan kode Anda untuk Kinerja yang lebih baik
  • Compiler dapat menangani manajemen memori
  • Tidak perlu menggunakan referensi lemah untuk diri sendiri dalam penutupan


Untuk detail, lihat: Buat non-escape menutup default


22
2017-10-24 10:28