कैसे सही ढंग से तर्क के साथ स्विफ्ट ब्लॉक में कमजोर आत्म संभाल


151

मेरे पास TextViewTableViewCell, मेरे पास एक ब्लॉक का ट्रैक रखने के लिए एक चर है और एक कॉन्फ़िगर विधि है जहां ब्लॉक को पास और सौंपा गया है।
यहाँ मेरी TextViewTableViewCellकक्षा है:

//
//  TextViewTableViewCell.swift
//

import UIKit

class TextViewTableViewCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet var textView : UITextView

    var onTextViewEditClosure : ((text : String) -> Void)?

    func configure(#text: String?, onTextEdit : ((text : String) -> Void)) {
        onTextViewEditClosure = onTextEdit
        textView.delegate = self
        textView.text = text
    }

    // #pragma mark - Text View Delegate

    func textViewDidEndEditing(textView: UITextView!) {
        if onTextViewEditClosure {
            onTextViewEditClosure!(text: textView.text)
        }
    }
}

जब मैं अपनी विधि में कॉन्फ़िगर विधि का उपयोग करता हूं cellForRowAtIndexPath, तो मैं जिस ब्लॉक से गुजरता हूं, उसमें कमजोर स्वयं का उपयोग कैसे ठीक से करता हूं।
यहां मेरे पास कमजोर स्वयं के बिना है:

let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {(text: String) in
   // THIS SELF NEEDS TO BE WEAK  
   self.body = text
})
cell = bodyCell

अद्यतन : मुझे निम्नलिखित का उपयोग करके काम करना है [weak self]:

let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {[weak self] (text: String) in
        if let strongSelf = self {
             strongSelf.body = text
        }
})
cell = myCell

जब मैं इसके [unowned self]बजाय करता हूं [weak self]और ifस्टेटमेंट निकालता हूं , तो ऐप क्रैश हो जाता है। यह कैसे के साथ काम करना चाहिए पर कोई विचार [unowned self]?


क्या आप नीचे दिए गए उत्तर को सही उत्तर के रूप में चुन सकते हैं? यह भी ध्यान दें कि अनजाने में आपको अपने बंद होने के भीतर स्वयं को मजबूत करने की आवश्यकता नहीं होगी। विख्यात यहाँ कमजोर से बेहतर है क्योंकि आपके सेल और व्यू कंट्रोलर का जीवन चक्र जुड़ा हुआ है।
इकुरामेडिया

1
मुझे लगता है कि [प्रसिद्ध स्वयं] अगर बेहतर विकल्प है, लेकिन मेरा ऐप क्रैश हो जाता है जब मैं इसका उपयोग करता हूं। उत्तर को बंद करने के लिए इसका उपयोग करके एक कोड नमूना देखना पसंद करेंगे।
नताशाTheRobot

1
डॉक्स से: "कमजोर संदर्भों की तरह, एक अज्ञात संदर्भ उस संदर्भ पर एक मजबूत पकड़ नहीं रखता है जो इसे संदर्भित करता है। एक कमजोर संदर्भ के विपरीत, हालांकि, एक अज्ञात संदर्भ को हमेशा मान दिया जाता है।" यदि आपका ऐप क्रैश होता है, तो यह है। संभावना है क्योंकि अनजान को रनटाइम पर शून्य मान पर लागू किया जा रहा है।
बिल पैटरसन

शायद मजबूत करने के लिए बाध्यकारी की तुलना में यहाँ एक गार्ड बयान का विज्ञापन करने के लिए बेहतर है। सिर्फ यह कहते हुए, यह बिल्कुल सही उम्मीदवार की तरह है :-D
डैनियल गैलास्को

@ नताशा आरोबोट, क्या वाक्य रचना [कमजोर स्व] है? उद्देश्य सी में पास होने वाले संदेश की तरह दिखता है। क्या आप कृपया प्रश्न में वाक्य रचना के बारे में थोड़ा और जोड़ सकते हैं।
विग्नेश

जवाबों:


178

यदि स्वयं को बंद उपयोग [कमजोर स्वयं] में शून्य किया जा सकता है ।

यदि स्वयं को बंद करने के उपयोग में शून्य नहीं होगा [अज्ञात स्व]

यदि यह दुर्घटनाग्रस्त हो जाता है जब आप [अज्ञात स्वयं] का उपयोग करते हैं, तो मुझे लगता है कि आत्म उस बंद होने के कुछ बिंदु पर शून्य है, यही वजह है कि आपको इसके बजाय [कमजोर आत्म] के साथ जाना पड़ा ।

मुझे वास्तव में मजबूत , कमजोर , और बंद में अज्ञात का उपयोग करने पर मैनुअल से पूरा खंड पसंद आया :

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

नोट: मैंने ब्लॉक के बजाय टर्म क्लोजर का उपयोग किया है जो कि नई स्विफ्ट टर्म है:

आईओएस में ब्लॉक (ऑब्जेक्टिव सी) और क्लोजर (स्विफ्ट) के बीच अंतर


7
Apple ने C भाषा एक्सटेंशन के लिए अपने पहले दस्तावेज़ में "क्लोज़र" को ब्लॉक कहा है। (ब्लॉक या क्लोजर पहले सी का एक एक्सटेंशन हैं। केवल MM ऑब्जेक्टिव-सी से संबंधित है।) यहां तक ​​कि मैं "क्लोजर" शब्द भी पसंद करता हूं, क्योंकि C में "ब्लॉक" बहुत बार यौगिक कथनों से संबंधित है, यह दोनों भाषाओं में एक प्रकार का गलत है, क्योंकि इसे एक बंद कहा जाता है, यहां तक ​​कि यह एक वस्तु (चर या स्थिर) पर बंद नहीं होता है।
अमीन नेगम-अवध

1
बहुत अच्छी तरह से जवाब दिया :)
iDevAmit

1
मेरा सुझाव है कि कभी उपयोग न करें unowned। यह आपके ऐप को क्रैश करने के जोखिम के लायक नहीं है।
काइल रेडफर्न जूल

32

अपने बंद में [unowned self]पहले रखो (text: String)...। इसे कैप्चर सूची कहा जाता है और क्लोजर में कैप्चर किए गए प्रतीकों पर स्वामित्व निर्देश देता है।


2
नामकरण के लिए धन्यवाद, मैं यह जानना चाहता था!
रोब ५४०

3
मुझे नहीं लगता कि यह उत्तर उपयोगी है। [विख्यात स्व] दुर्घटना के निष्पादन के दौरान स्वयं शून्य हो जाता है तो दुर्घटनाग्रस्त हो जाएगा
यूनुस नेदिम मेहेल

3
वहाँ बिल्कुल कोई कारण नहीं में बिना स्वामित्व वाले का उपयोग करने के लिए, की तुलना में (1) अन्य अत्यंत असामान्य स्थितियों प्रदर्शन के लिए, और (2) (इस यहाँ और प्रोग्रामिंग की 99.999% में पूरी तरह से अप्रासंगिक है) एक शैली प्रवर्तन मामले के रूप में। बयान "आपको हमेशा कमजोर का उपयोग करना चाहिए, कभी भी अमान्य नहीं" बहुत ही उचित है।
फेटी

29

** स्विफ्ट 4.2 के लिए आदर्श:

@Koen टिप्पणी के रूप में, तेजी से 4.2 की अनुमति देता है:

guard let self = self else {
   return // Could not get a strong reference for self :`(
}

// Now self is a strong reference
self.doSomething()

पुनश्च: चूंकि मैं कुछ अप-वोट कर रहा हूं, इसलिए मैं पढ़ने से बचने की सिफारिश करना चाहूंगा ।

EDITED: जैसा कि @ tim-vermeulen ने टिप्पणी की है, क्रिस लट्टनर ने 22 जनवरी 19:51:29 सीएसटी 2016 पर कहा, इस ट्रिक का इस्तेमाल स्वयं पर नहीं किया जाना चाहिए, इसलिए कृपया इसका उपयोग न करें। गैर बचने वाले क्लोजर की जानकारी और @gbk से कैप्चर सूची उत्तर की जांच करें।

जो लोग कब्जा सूची में [कमजोर आत्म] का उपयोग करते हैं, ध्यान दें कि आत्म शून्य हो सकता है, इसलिए पहली बात मैं एक गार्ड के बयान के बारे में जांच कर रहा हूं

guard let `self` = self else {
   return
}
self.doSomething()

यदि आप सोच रहे हैं कि उद्धरण चिह्नों के आस-पास क्या है, selfतो नाम को इस , कमजोर या जो भी हो उसे बदलने की आवश्यकता के बिना बंद के अंदर स्वयं का उपयोग करने के लिए एक समर्थक चाल है ।



2
मैं यह सुनिश्चित करने के लिए स्थानीय "स्व" "strongSelf" को कॉल करता हूं कि यह डिफ़ॉल्ट स्वयं के साथ भ्रमित नहीं है और यह स्पष्ट करना आसान है कि क्या आपने एक मजबूत आत्म संदर्भ के लिए पहरा दिया है।
जस्टिन स्टेनली

1
इसका उपयोग नहीं किया जाना चाहिए, क्योंकि यह एक कंपाइलर बग है: lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160118/…
टिम वर्म्यूलेन

1
मुझे लगता है कि ऊपर दिए गए लिंक में क्रिस लैटनर की टिप्पणी वैरिएबल का नामकरण self(बैकटिक्स में) नहीं है। इसे कुछ और नाम दें जैसे कि nonOptionalSelf और यह ठीक रहेगा।
आउटऑनवेकेंड

1
आजकल (स्विफ्ट 4.2) { [weak self] in guard let self = self else { return }का उपयोग बिना बैकटिक्स के किया जा सकता है, और वास्तव में इसका समर्थन किया जाता है: github.com/apple/swift-evolution/blob/master/proposals/…
Koen।

26

कैप्चर सूची का उपयोग करें

कैप्चर सूची को परिभाषित करना

कैप्चर सूची में प्रत्येक आइटम एक वर्ग उदाहरण (जैसे स्वयं) के संदर्भ में कमजोर या अज्ञात कीवर्ड की एक जोड़ी है या कुछ मूल्य के साथ आरंभिक चर (जैसे प्रतिनिधि = आत्म.लेगिट!)। ये जोड़ियां चौकोर ब्रेसिज़ की एक जोड़ी के भीतर लिखी जाती हैं, जिन्हें कॉमा द्वारा अलग किया जाता है।

क्लोजर की पैरामीटर सूची से पहले कैप्चर सूची रखें और यदि वे उपलब्ध कराए गए हैं तो टाइप करें:

lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    // closure body goes here 
} 

यदि कोई बंद पैरामीटर सूची या रिटर्न प्रकार निर्दिष्ट नहीं करता है, क्योंकि वे संदर्भ से अनुमान लगाया जा सकता है, तो कैप्चर सूची को समापन के बहुत ही शुरुआत में रखें, इसके बाद कीवर्ड:

lazy var someClosure: Void -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here
}

अतिरिक्त स्पष्टीकरण


3
आपने "स्वयं" के लिए उपयोग नहीं किया है जिसका अर्थ है कि आप यह सुनिश्चित करते हैं कि जब आप इसे एक्सेस करते हैं तो "स्व" अभ्यस्त हो। फिर आपने "self.delegate" (जिसका अर्थ यह भी है कि आपको पता है कि यह निश्चित रूप से शून्य होगा) को कमजोर संस्करण में नियत करने के लिए बल प्रयोग नहीं किया था। यदि आप यह सुनिश्चित करने के लिए जानते हैं कि "self.delegate" अभ्यस्त हो जाएगा, तो कमजोर के बजाय "प्रतिनिधि" पर अज्ञात का उपयोग क्यों न करें?
रोनी लेशेस

26

EDIT: लाइटमैन द्वारा एक अद्यतन समाधान का संदर्भ

लाइटमैन का समाधान देखें । अब तक मैं उपयोग कर रहा था:

input.action = { [weak self] value in
    guard let this = self else { return }
    this.someCall(value) // 'this' isn't nil
}

या:

input.action = { [weak self] value in
    self?.someCall(value) // call is done if self isn't nil
}

आमतौर पर आपको पैरामीटर प्रकार निर्दिष्ट करने की आवश्यकता नहीं होती है यदि यह अनुमान है।

आप पैरामीटर को पूरी तरह से छोड़ सकते हैं यदि कोई नहीं है या यदि आप इसे $0बंद के रूप में संदर्भित करते हैं :

input.action = { [weak self] in
    self?.someCall($0) // call is done if self isn't nil
}

पूर्णता के लिए बस; यदि आप किसी फ़ंक्शन को बंद कर रहे हैं और पैरामीटर नहीं है @escaping, तो आपको एक की आवश्यकता नहीं है weak self:

[1,2,3,4,5].forEach { self.someCall($0) }

9

तेजी से 4.2 के अनुसार हम कर सकते हैं:

_ = { [weak self] value in
    guard let self = self else { return }
    print(self) //👈 will never be nil
}()

अन्य के समान समाधान हैं, लेकिन "यह" C ++ IMHO है। "strongSelf" एक Apple सम्मेलन है और जो कोई भी आपके कोड को देखता है उसे पता चल जाएगा कि व्हाट्सएप चल रहा है।
डेविड एच।

1
@ डेविड एच आईएमओ वाक्यांश strongSelfस्पष्ट रूप से चर का अर्थ / साइडफैक्ट बताते हैं जो कोड अधिक लंबी प्रकृति का होने पर अच्छा है। आपकी राय की सराहना करते हैं, हालांकि यह नहीं पता है कि c ++ ने इस तरह के वाक्यांशों का उपयोग किया है।
जोंक

3
स्विफ्ट 4.2 के रूप में आप उपयोग न guard let self = self else { return }करने के लिए उपयोग कर सकते हैं [weak self]: github.com/apple/swift-evolution/blob/master/proposals/…
Amer Hukic

@AmerHukic ic
eonist


3

आप ब्लॉक के अपने मापदंडों से पहले कैप्चर सूची में [कमजोर स्वयं] या [अज्ञात स्वयं] का उपयोग कर सकते हैं। कैप्चर सूची वैकल्पिक सिंटैक्स है।

[unowned self]यहाँ अच्छा काम करता है क्योंकि सेल कभी भी शून्य नहीं होगा। अन्यथा आप उपयोग कर सकते हैं[weak self]


1
सेल स्वयं नहीं है, वह सेल क्लास पर नहीं है, वह शायद एक दृश्य केंद्र पर है ...
जुआन बोरो

0

अगर आप शायद जरूरत से ज्यादा दुर्घटनाग्रस्त हो रहे हैं [कमजोर आत्म]

मेरा अनुमान है कि आप जिस ब्लॉक का निर्माण कर रहे हैं वह किसी तरह अभी भी वायर्ड है।

एक CreateForReuse बनाएँ और उस के अंदर onTextViewEditClosure ब्लॉक को साफ़ करने का प्रयास करें।

func prepareForResuse() {
   onTextViewEditClosure = nil
   textView.delegate = nil
}

देखें कि क्या दुर्घटना को रोकता है। (यह सिर्फ एक अनुमान है)।


0

बंद और मजबूत संदर्भ चक्र [के बारे में]

जैसा कि आप जानते हैं कि स्विफ्ट का बंद होना उदाहरण पर कब्जा कर सकता है। इसका मतलब है कि आप selfएक क्लोजर के अंदर उपयोग करने में सक्षम हैं । विशेष रूप से escaping closure[के बारे में]strong reference cycle जो एक बना सकते हैं । वैसे आपको स्पष्ट रूप से selfअंदर का उपयोग करना होगा escaping closure

स्विफ्ट क्लोजर में Capture Listसुविधा है जो आपको ऐसी स्थिति से बचने और एक संदर्भ चक्र को तोड़ने की अनुमति देता है क्योंकि कैप्चर किए गए उदाहरण के लिए एक मजबूत संदर्भ नहीं है। कैप्चर सूची तत्व एक जोड़ी weak/ unownedऔर वर्ग या चर का संदर्भ है।

उदाहरण के लिए

class A {
    private var completionHandler: (() -> Void)!
    private var completionHandler2: ((String) -> Bool)!

    func nonescapingClosure(completionHandler: () -> Void) {
        print("Hello World")
    }

    func escapingClosure(completionHandler: @escaping () -> Void) {
        self.completionHandler = completionHandler
    }

    func escapingClosureWithPArameter(completionHandler: @escaping (String) -> Bool) {
        self.completionHandler2 = completionHandler
    }
}

class B {
    var variable = "Var"

    func foo() {
        let a = A()

        //nonescapingClosure
        a.nonescapingClosure {
            variable = "nonescapingClosure"
        }

        //escapingClosure
        //strong reference cycle
        a.escapingClosure {
            self.variable = "escapingClosure"
        }

        //Capture List - [weak self]
        a.escapingClosure {[weak self] in
            self?.variable = "escapingClosure"
        }

        //Capture List - [unowned self]
        a.escapingClosure {[unowned self] in
            self.variable = "escapingClosure"
        }

        //escapingClosureWithPArameter
        a.escapingClosureWithPArameter { [weak self] (str) -> Bool in
            self?.variable = "escapingClosureWithPArameter"
            return true
        }
    }
}
  • weak- अधिक बेहतर, जब संभव हो तो इसका उपयोग करें
  • unowned - इसका उपयोग तब करें जब आप सुनिश्चित हों कि उदाहरण के मालिक का जीवनकाल बंद होने से बड़ा है
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.