2016-01-20 13 views
5

इम परीक्षण स्विफ्ट 2.0 और नए कीवर्ड defer एक खेल का मैदान में:समारोह में स्थगित स्विफ्ट में काम नहीं किया 2.0

func branch() -> String { 

    var str = "" 

    defer { str += "xxx" } 
    str += "1" 

    let counter = 3; 

    if counter > 0 { 
     str += "2" 
     defer { str += "yyy" } 
     str += "3" 
    }  
    str += "4" 

    return str  
} 

let bran = branch() 

मैं bran उम्मीद "123yyy4xxx" हो सकता है, लेकिन यह वास्तव में "123yyy4"

क्यों है क्या मेरा डिफ्रर (str += "xxx") अपेक्षित काम नहीं करता है?

+1

यह काम करता है लेकिन 'defer' शुरू हो जाती है _after_ गुंजाइश पहले बाहर चलाता है इसलिए 'रिटर्न स्ट्र' को तब कॉल किया जाता है जब दायरा समाप्त हो जाता है और यह आपके 'डिफियर' को कॉल करता है और स्थानीय उदाहरण में 'xxx "' जोड़ता है जो _after_ मान रिटर्न होता है। – holex

उत्तर

7

एक स्थगित कथन निष्पादन को रोकता है जब तक कि वर्तमान दायरा बाहर नहीं निकलता है।

जो सेब कहता है। इसलिए वापसी विवरण के बाद स्थगित बयान निष्पादित किया जाएगा। यही कारण है कि आप अपेक्षित परिणाम नहीं देख सकते हैं।

5

सबसे पहले: defer निष्पादित हो जाता है क्योंकि आप इसे print(str) जोड़ते समय स्पष्ट रूप से देख सकते हैं।

अब समझाने के लिए क्यों दिए गए मान बदली हुई मूल्य को प्रतिबिंबित नहीं करता:
इस का कारण यह है कि String अपरिवर्तनीय है - जब भी आप str += something बारे में आप पूरी तरह से नया String उदाहरण बना सकते हैं और str अंदर यह दुकान।

यदि आप return str लिखते हैं जो str का वर्तमान उदाहरण देता है जो 123yyy4 है। फिर defer को पूरी तरह से नया और असंबंधित String123yyy4xxxstr असाइन किया जाता है। लेकिन str के अंदर संग्रहीत पिछले String ऑब्जेक्ट को नहीं बदलेगा, यह बस इसे ओवरराइट करता है और इसलिए return को प्रभावित नहीं करता है जो पहले से ही "हुआ" है।

आप NSMutableString का उपयोग करने के बजाय आप हमेशा ही उदाहरण पर कार्यवाही करेंगे अपनी प्रक्रिया बदल देते हैं और परिणाम होगा इसलिए सही ढंग से उत्पादन 123yyy4xxx:

func branch() -> NSMutableString { 
    var str = NSMutableString() 
    defer { str.appendString("xxx") } 
    str.appendString("1") 
    let counter = 3; 
    if counter > 0 { 
     str.appendString("2") 
     defer { str.appendString("yyy") } 
     str.appendString("3") 
    } 
    str.appendString("4") 
    return str 
} 


let bran1 = branch() 

कि कोड में वापसी str में संग्रहीत उदाहरण देता है और defer बदलता है कि उदाहरण, यह एक नया उदाहरण असाइन नहीं करता है लेकिन पहले से मौजूद एक को बदलता है।

  • इसे बदलने
  • के बाद defer ब्लॉक में str बदलने से पहले

      return
    • के समय
    • :

      स्पष्टीकरण खातिर आप विभिन्न चरणों में str की स्मृति पते को देखने का प्रयास कर सकते हैं

    NSMutableString के लिए सभी तीन मामलों में एक ही स्मृति पता अर्थ होगा जी कि उदाहरण वही रहता है। String एक हालांकि दो अलग-अलग मेमोरी पतों को प्रिंट करता है जिसके परिणामस्वरूप लौटा हुआ स्ट्रिंग someAddress पर इंगित करता है और स्थगित एक someOtherAddress पर इंगित करता है।

    +3

    ध्यान दें कि 'unsafeAddressOf() 'एक स्विफ्ट स्ट्रिंग (या किसी भी गैर-वर्ग प्रकार) के साथ पूरी तरह से व्यर्थ है, यह अस्थायी रूप से ब्रिज किए गए एनएसएसटींग का पता देता है: http://stackoverflow.com/questions/32638879/swift-strings- और स्मृति-पतों। –

    +0

    @ मार्टिनआर हम्म:/किसी भी आइडिया को स्ट्रिंग इंस्टेंस के मेमोरी चेंज को विज़ुअलाइज़ करने के बजाय मुझे क्या उपयोग करना चाहिए? – luk2302

    7

    ग्रेग सही है और आप अपने कोड के साथ एक ही परिणाम प्राप्त करना चाहते हैं तो आप इसे इस तरह कर सकते हैं:

    var str = "" 
    
    func branch() { 
    
        str = "" 
        defer { str += "xxx" } 
        str += "1" 
    
    
        let counter = 3 
    
        if counter > 0 { 
         str += "2" 
         defer { str += "yyy" } 
         str += "3" 
        } 
        str += "4" 
    
    } 
    
    branch() 
    str //"123yyy4xxx" 
    
    +2

    वैश्विक चर आधारित समाधान लगभग कभी भी अच्छे समाधान नहीं होते हैं। आप 'str' चर को रीसेट करना भी भूल गए हैं, इसलिए 'शाखा()' कई बार कॉल करने से अलग-अलग परिणाम मिलते हैं। – Cristik

    +0

    कोड अपडेट और आपके सुझाव के लिए धन्यवाद। –

    संबंधित मुद्दे