स्विफ्ट वैकल्पिक भागने क्लोजर पैरामीटर


162

दिया हुआ:

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

क्या कोई प्रकार का completionपैरामीटर (और action) बनाने के लिए Action?और भी रखने के लिए है @escaping?

प्रकार बदलने से निम्नलिखित त्रुटि होती है:

@ से बचने की विशेषता केवल फ़ंक्शन प्रकारों पर लागू होती है

@escapingविशेषता को हटाते हुए, कोड संकलित करता है और चलाता है, लेकिन सही नहीं लगता है क्योंकि completionक्लोजर फ़ंक्शन के दायरे से बच रहा है।


21
"निकाल रहा है @escapingविशेषता, कोड compiles और रन" - क्योंकि, में वर्णित के रूप कि के एसआर 2444 , Action?डिफ़ॉल्ट रूप से, से बचने के है। इसलिए, @escapingवैकल्पिक क्लोजर का उपयोग करते समय हटाने से आपको जो चाहिए वह पूरा होता है।
रोब


टाइप उर्फ ​​क्लोजर बच रहे हैं
माशिह

यहां ओले बेगेमन का एक उत्कृष्ट लेख है जो बताता है कि यह क्यों हो रहा है और यदि आप वैकल्पिक पैरामीटर @noescape चाहते हैं तो कुछ वर्कअराउंड हैं।
Senseful

जवाबों:


122

वहाँ एक है एसआर 2552 रिपोर्टिंग कि @escapingसमारोह प्रकार उर्फ पहचान नहीं कर रहा। इसलिए त्रुटि है @escaping attribute only applies to function types। आप फ़ंक्शन हस्ताक्षर में फ़ंक्शन प्रकार का विस्तार करके समाधान कर सकते हैं:

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

संपादित 1 :

मैं वास्तव में एक xcode 8 बीटा संस्करण के अंतर्गत था जहां बग SR-2552 अभी तक हल नहीं हुआ था। उस बग को ठीक करते हुए, एक नया (जो आप सामना कर रहे हैं) पेश किया जो अभी भी खुला है। SR-2444 देखें ।

वैकल्पिक हल @Michael Ilseman एक अस्थायी समाधान के रूप में बताया हटाने है @escapingवैकल्पिक समारोह प्रकार से विशेषता, कि बचने के रूप में समारोह रखना

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

संपादित करें 2 :

एसआर 2444 बंद स्पष्ट रूप से बताते हुए किया गया है कि मानकों की स्थिति में बंद नहीं कर रहे हैं से बचने और के साथ चिह्नित किए जाने की उन्हें जरूरत @escapingउन्हें भागने बनाने के लिए है, लेकिन वैकल्पिक पैरामीटर रहे परोक्ष बचने, के बाद से ((Int)->())?की एक समानार्थी शब्द है Optional<(Int)->()>, वैकल्पिक बंद से बचने कर रहे हैं।


5
अब मिल रहा है@escaping may only be applied to parameters of function type func doStuff(stuff: String, completion: (@escaping ()->())?) {
लेस्काई इयोनेल सेप

1
a temporary solution is remove the @escaping attribute from optional function type, that keep the function as escaping. क्या आप इसे आगे बता सकते हैं? स्विफ्ट 3 में डिफ़ॉल्ट सिमेंटिक गैर-भागने वाला है। हालांकि यह @ केसिंग के बिना संकलित है मुझे डर है कि इसे गैर-भागने के रूप में माना जाएगा। क्या यह सच नहीं है?
पाट नीमेयर 21

49
आगे पढ़ने पर मैं देखता हूं कि एसआर -2444 कहता है कि सभी वैकल्पिक क्लोजर को बचने के रूप में माना जाता है, जो कि एक पूरक बग है :) मैं यह मानकर चलता हूं कि जब यह तय हो जाएगा तो संकलन हमें बदलाव करने के लिए चेतावनी देगा।
पाट नीमेयर 21

शायद थोड़ा सा विषय; लेकिन यह कैसे काम करता है @autoclosure? वहाँ एक ही त्रुटि मिलती है ...
Gee.E

इसके बिना काम कर रहा है @esuring __ func doStuff (सामान: स्ट्रिंग, पूर्णता: () -> ())?) {
неннур Мезитов

226

से: स्विफ्ट-उपयोगकर्ता मेलिंग सूची

मूल रूप से, @ पैरामीटर केवल फ़ंक्शन पैरामीटर स्थिति में बंद होने पर मान्य है। Noescape-by-default नियम केवल फ़ंक्शन पैरामीटर स्थिति में इन क्लोजर पर लागू होता है, अन्यथा वे बच रहे हैं। एग्रीगेट्स, जैसे कि संबद्ध मान (जैसे वैकल्पिक), ट्यूपल्स, संरचनाएं आदि के साथ एनम, यदि उनके पास क्लोजर हैं, तो क्लोजर के लिए डिफ़ॉल्ट नियमों का पालन करें जो फ़ंक्शन पैरामीटर स्थिति में नहीं हैं, अर्थात वे बच रहे हैं।

तो वैकल्पिक फ़ंक्शन पैरामीटर @ डिफ़ॉल्ट रूप से डिफ़ॉल्ट है।
@noeascape केवल डिफ़ॉल्ट रूप से फ़ंक्शन पैरामीटर पर लागू होता है।


7
मुझे लगता है कि यह इस विषय में सबसे महत्वपूर्ण जानकारी जोड़ता है, इसका उत्तर स्वीकार किया जाना चाहिए।
डेमियन ड्यूडीज़

तर्कयुक्त उत्तर। यह कितना संभावित है कि यह बदल सकता है?
गोल्डनजियो नोव

2
यह समझ में आता है क्योंकि तकनीकी (()->Void)?रूप से यह कहना वैसा ही है जैसा आपके पास है Optional<()->Void>और Optionalस्वामित्व बनाए रखने के लिए इसे केवल @escapingकार्य स्वीकार करना होगा। मैं तीसरा हूं कि यह स्वीकृत उत्तर होना चाहिए। धन्यवाद।
डीन केली

22

मैं एक समान समस्या में भाग गया क्योंकि मिश्रण @escapingऔर गैर- @escapingबहुत भ्रामक है, खासकर यदि आपको क्लोजर को पास करने की आवश्यकता होती है।

मैंने क्लोजर पैरामीटर के माध्यम से एक नो-ऑप डिफ़ॉल्ट मान असाइन करना समाप्त किया = { _ in }, जिसके बारे में मुझे लगता है कि यह अधिक समझ में आता है:

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

यह कार्यान्वयन में साफ और सुंदर है।
फ्रेड फॉस्ट

2
क्या होगा अगर मैं जांचना चाहता हूं कि क्या यह ब्लॉक शून्य / खाली है?
व्याचेस्लाव गेर्चिकोव

2
Bummer, यह एक प्रोटोकॉल विधि के लिए काम नहीं करता है। "प्रोटोकॉल पद्धति में डिफ़ॉल्ट तर्क की अनुमति नहीं है" (Xcode 8.3.2)।
माइक टवेर्न

17

मैं इसे स्विफ्ट 3 में बिना किसी चेतावनी के केवल इस तरह से काम कर रहा हूं:

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

4

उदाहरण में समझने के लिए महत्वपूर्ण बात यह है कि यदि आप बदल रहा है Actionकरने के लिए Action?बंद है भागने। तो, आप क्या प्रस्ताव करते हैं:

typealias Action = () -> ()

var action: Action? = { }

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

ठीक है, अब हम फोन करेंगे 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
        }
    }
}

खैर, यह आवश्यकता केवल बंद होने से बचने के लिए पैदा होती है। इसलिए बंद होने से बच रहा है। इसलिए आप इसे भागने से चिह्नित नहीं करते हैं - यह पहले से ही बच रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.