Svift-da @escaping va @nonescaping yopilishi nimani anglatadi?

Kodni ishlatish paytida, har qanday funktsiyalar bilan ishlayotganingizda, @escaping yoki @nonescaping atributlari bilan ishlashingiz mumkin. Ever Bu nimani anglatishini o'ylab ko'rish uchun vaqt ajratganmisiz? Shunday qilib, bu erda biz ushbu shartlar haqida muhokama qilmoqchimiz.

Yopish nima?

Yopishlar - bu sizning kodingizda ishlatilishi mumkin bo'lgan o'z-o'zidan ishlab chiqarilgan bloklar.

Swift 1.x va Swift 2.x da yopilish parametr sukut bo'yicha @escaping bo'lib, bu funktsiyani bajarishda yopilishning oldini olish mumkinligini anglatadi. yopilish parametrlaridan qochishni istamasangiz, uni @nonescaping deb belgilang.

Swift 3.x-da Apple o'zgarishni amalga oshirdi: yopilish parametrlari sukut bo'yicha @ nonescapingga aylandi, agar yopilishni bajarishni xohlamasangiz @escaping deb belgilansangiz, yopilish funksiya tanasi bilan ham amalga oshiriladi. Nega Apple bu o'zgartirishni kiritdi? The Buni muhokama oxirida muhokama qilaylik.

1. @konsepsiyani yopish:

Funktsiya argumenti sifatida yopilishdan o'tishda, funktsiya tanasi bilan yopiladi va kompilyatorni qaytaradi. Amalga oshirish tugagach, o'tgan yopilish doirasidan chiqadi va xotirada boshqa mavjud bo'lmaydi.

@ Nonescaping yopilishining hayotiy davri:
 1. Funktsiyani chaqirish paytida, yopish funktsiyasini argument sifatida o'tkazing.
 2. Funktsiya bilan qo'shimcha ishlarni bajaring.
 3. Funktsiya yopishni amalga oshiradi.
 4. Funktsiya kompilyatorni orqaga qaytaradi.

Masalan:

func getSumOf (qator: [Int], ishlov beruvchi: ((Int) -> Void)) {
        // 2-bosqich
        var sum: Int = 0
        massivdagi qiymat uchun {
            sum + = qiymat
        }
        
        // 3-qadam
        ishlov beruvchi (summa)
    }
    
    func doSomething () {
        // 1-qator
        self.getSumOf (qator: [16,756,442,6,23]) {[kuchsiz o'zini] (yig'indisi) ichida
            bosib chiqarish (sum)
            // 4-qadam, bajarishni tugatish
        }
    }
// Berilgan barcha raqamlarning yig'indisini chiqaradi.

Bu erda biz faqat funktsiyaning tanasi oxirida bajariladigan yopilish bilan funktsiyani chaqirdik.
Shunday qilib, biz yopilish buyrug'idan qochib ketmayapmiz. 4-bosqich bajarilishi bilan yopilish xotirada mavjud bo'lmaydi.

2.Sescaping yopilishi:

Funktsiya argumenti sifatida yopilgandan so'ng, yopilish keyinchalik bajarilishi uchun saqlanib qoladi va funktsiya tanasi bajariladi, kompilyatorni qaytaradi. Bajarish tugagandan so'ng, yopilish yopilgan joyning hajmi mavjud va u yopilish jarayoni tugaguncha xotirada qoladi.
 Yopilishdan qochishning bir necha yo'li mavjud:

  • Saqlash: Xotirada mavjud bo'lgan yopilishni saqlab qolish kerak bo'lganda, qo'ng'iroq qilish funktsiyasining o'tmishi bajariladi va kompilyatorni qaytarib beradi. (API javobini kutish kabi)
  • Asinxron ijro: Siz yopilishni navbatma-navbat bajarayotganda, navbat kelgusida ishlatilishi uchun siz xotirada xotirani saqlab qoladi. Bunday holda siz yopilish qachon amalga oshirilishini bilmayapsiz.

Agar siz ushbu tanlov yordamida yopilishdan foydalansangiz, tezkor kompilyator xatoni ko'rsatadi.

@Escaping yopilishining hayotiy davri:
1. Funktsiyani chaqirish paytida, yopish funktsiyasini argument sifatida o'tkazing.
2. Biroz qo'shimcha funktsiyani bajaring.
3. Funktsiya yopilishini asenkron yoki saqlangan holda bajaradi.
4. Funktsiya kompilyatorni orqaga qaytaradi.

1-misol (Saqlash):

var shikoyatHandler: ((Int) -> Bo'sh joy)?
    func getSumOf (qator: [Int], ishlov beruvchi: @escaping ((Int) -> Void)) {
        // 2-bosqich
       // bu erda men faqat loopni olaman, masalan, bu API chaqiruvi kabi boshqa narsa bo'ladi
       var sum: Int = 0
        massivdagi qiymat uchun {
            sum + = qiymat
        }
// 3-qadam
        self.complitionHandler = ishlov beruvchi
    }
    
    func doSomething () {
        // 1-qator
        self.getSumOf (qator: [16,756,442,6,23]) {[kuchsiz o'zini] (yig'indisi) ichida
            bosib chiqarish (sum)
            // 4-qadam, bajarishni tugatish
        }
    }
// Bu erda biz kelajakda foydalanish uchun yopilishni saqlamoqdamiz.
// Bu berilgan barcha raqamlarning yig'indisini chiqaradi.

2-misol (Asinxron ijro):

func getSumOf (qator: [Int], ishlov beruvchi: @escaping ((Int) -> Void)) {
        // 2-bosqich
        var sum: Int = 0
        massivdagi qiymat uchun {
            sum + = qiymat
        }
        // 3-qadam
        Globals.delay (0.3, yopilish: {
            ishlov beruvchi (summa)
        })
    }
    
    func doSomething () {
        // 1-qator
        self.getSumOf (qator: [16,756,442,6,23]) {[kuchsiz o'zini] (yig'indisi) ichida
            bosib chiqarish (sum)
            // 4-qadam, bajarishni tugatish
        }
    }
// Bu erda biz 0.3 soniya kechikish bilan yopishni chaqiramiz
// Bu berilgan barcha raqamlarning yig'indisini chiqaradi.

Bu erda biz @escaping atributining ma'nosi bilan tanishamiz. Shunday qilib, siz o'chirishni bajarishdan qochishingiz kerak bo'lsa, Swift 3-da @escaping atributidan foydalaning, yuqorida ko'rsatilgan kompilyatorning xatosi, @escaping atributidan foydalanib, yopilgandan so'ng yo'qoladi.

Nima uchun ular sukut bo'yicha @nonescaping qildilar?

Odatdagidek, qochib qutulishning foydasi ko'p. Eng muhim afzalliklar kompilyator tomonidan ishlash va kodni optimallashtirishdir, chunki agar kompilyator yopilish nimaligini bilsa, yopish uchun xotira ajratilishi haqida g'amxo'rlik qiladi.

Va yana biri shundaki, biz o'zini yopilmasdan yopishda muammosiz foydalanishimiz mumkin, chunki yopilish funktsiya qaytgunga qadar amalga oshiriladi, shuning uchun o'zini o'zi bo'ladi. Zaif o'zini o'zi ishlatishga hojat yo'q, bu uning qo'shimcha xususiyati .

Swift 3-da, yopilishlar asossiz bo'lmaydi, agar biz istamasak, @escaping-dan foydalanishimiz mumkin. Qochib ketmaydigan yopilish funktsiya qaytmasdan oldin bajariladi.
Yopish paytida har doim zaif o'zini ishlatishni unutmang.

O'qiganingiz uchun rahmat, iltimos, agar ushbu to'plam kabi bo'lsa, tavsiya belgisini bosing hit. Savollar? Ularni sharhda qoldiring.