Swift isteğe bağlı kaçan kapatma parametresi


162

Verilen:

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()

completionParametre (ve action) türünü yapmanın Action?ve saklamanın bir yolu var @escapingmı?

Türün değiştirilmesi aşağıdaki hatayı verir:

@escaping niteliği yalnızca işlev türleri için geçerlidir

Çıkarma @escapingniteliğini, kod derler ve ishal, ancak o zamandan beri doğru gibi görünmüyor completionkapatma fonksiyonunun kapsamını kaçıyor.


21
"Çıkarma @escapingniteliği, kod derler ve çalışır" - açıklandığı gibi, çünkü en SR-2444 , Action?kaçan, varsayılan olarak vardır. Bu nedenle, @escapingisteğe bağlı kapağı kullanırken çıkarmak , ihtiyacınız olanı başarır.
Rob


tip takma ad kapanıyor
Masih

İşte Ole Begemann'ın neden olduğunu açıklayan mükemmel bir makale ve isteğe bağlı parametrelerin @noescape olmasını istiyorsanız bazı geçici çözümler.
Senseful

Yanıtlar:


122

İşlev türü diğer adını tanımayan bir SR-2552 bildirimi var @escaping. bu yüzden hata @escaping attribute only applies to function types. işlev imzasındaki işlev türünü genişleterek geçici çözümü yapabilirsiniz:

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()

DÜZENLEME 1 ::

Aslında hata SR-2552 henüz çözülmedi bir xcode 8 beta sürümü altında idi. bu hatayı düzelttikten sonra, hala açık olan yeni bir hata (karşı karşıya olduğunuz) tanıttı. bkz. SR-2444 .

Geçici çözüm @Michael Ilseman geçici bir çözüm olarak işaret kaldırmak olduğunu @escapingopsiyonel fonksiyon türünden niteliği, kaçan olarak işlev tutmak .

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

DÜZENLEME 2 ::

SR-2444 parametreler pozisyonlarda kapanışları çok açık şekilde ifade kapalı edilmiştir değildir kaçan ve işaretlenecektir için onlara ihtiyacımız @escapingisteğe bağlı parametreler onları kaçan yapmak, ancak edilir beri, örtük kaçan ((Int)->())?bir eş olduğunu Optional<(Int)->()>, isteğe bağlı kapanışları kaçmaktadır.


5
Şimdi alma@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. Bunu daha fazla açıklayabilir misiniz? Hızlı 3'teki varsayılan semantik kaçmaz. @Escaping olmadan derlenmesine rağmen korkmuyorum kaçış olarak muamele ile sorunlara neden olacaktır. Bu doğru değil mi?
Pat Niemeyer

49
Daha fazla okuduktan sonra SR-2444'ün tüm isteğe bağlı kapakların kaçış olarak ele alındığını söylediğini görüyorum, bu tamamlayıcı bir hatadır :) Sabitlendiğinde derlemenin değişikliği yapmak için bizi uyaracağını varsayacağım.
Pat Niemeyer

Belki biraz konu dışı; ama bu nasıl çalışır @autoclosure? Biri orada aynı hatayı alır ...
Gee.E

@escaping __ func doStuff olmadan çalışıyor (stuff: String, completion: (() -> ())?) {
Феннур Мезитов

226

from: swift-kullanıcıları posta listesi

Temel olarak, @escaping yalnızca işlev parametresi konumundaki kapaklarda geçerlidir. Noescape-by-default kuralı, yalnızca işlev parametresi konumundaki bu kapaklar için geçerlidir, aksi takdirde kaçarlar. İlişkili değerlere sahip numaralandırmalar (örn. İsteğe bağlı), tuples, yapılar vb. Gibi birleştirilmişler, eğer kapanışları varsa, işlev parametresi konumunda olmayan, yani kaçmakta olan kapanmalar için varsayılan kuralları izleyin.

Bu nedenle isteğe bağlı işlev parametresi varsayılan olarak @ çıkış şeklindedir.
@noeascape varsayılan olarak işlev parametresine uygulanır.


7
Bu konuya en önemli bilgileri eklediğini düşünüyorum, cevap kabul edilmelidir.
Damian Dudycz

Gerekçeli cevap. Bunun değişmesi ne kadar olası?
GoldenJoe

2
Teknik olarak söylemek (()->Void)?, sahip olduğunuzu söylemekle aynı olduğundan Optional<()->Void>ve Optionalsahipliği korumak için sadece @escapingişlevleri kabul etmek zorunda olduğu için bu mantıklıdır . Bunun kabul edilen cevap olması için üçüncüyüm. Teşekkür ederim.
Dean Kelly

22

Benzer bir sorunla karşılaştım, çünkü karıştırma @escapingve @escapingözellikle de kapakları kapatmanız gerekiyorsa çok kafa karıştırıcı değil.

Kapanış parametresine no-op varsayılan değeri atayarak sona erdi = { _ in }, bence daha mantıklı:

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

Bu temiz ve uygulamada güzel.
Fred Faust

2
Bu bloğun sıfır / boş olup olmadığını kontrol etmek istersem ne olur?
Vyachaslav Gerchicov

2
Bummer, bu bir protokol yöntemi için çalışmaz. "Bir protokol yönteminde varsayılan bağımsız değişkene izin verilmiyor" (Xcode 8.3.2).
Mike Taverne

17

Swift 3'te herhangi bir uyarı yapmadan çalıştırabildim:

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

4

Örnekte anlamak önemlidir şey değiştirirseniz olmasıdır Actioniçin Action?kapatma edilir kaçan. Öyleyse önerdiğiniz şeyi yapalım:

typealias Action = () -> ()

var action: Action? = { }

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

Tamam, şimdi arayacağız 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
        }
    }
}

Bu gereklilik sadece kaçan kapaklar için ortaya çıkar. Yani kapanış kaçıyor. Bu yüzden kaçtığını işaretlemiyorsunuz - zaten kaçıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.