स्विफ्ट: संदर्भ द्वारा पास सरणी?


125

मैं अपनी स्विफ्ट Array account.chatsको chatsViewController.chatsसंदर्भ द्वारा पास करना चाहता हूं (ताकि जब मैं चैट को जोड़ूं account.chats, तब chatsViewController.chatsभी इंगित करता हूं account.chats)। यानी, मैं नहीं चाहता कि account.chatsपरिवर्तन की लंबाई होने पर दो सरणियों को अलग करूं ।


1
मैं समाप्त हो गया बस बनाने accountएक वैश्विक चर और परिभाषित करने chatsकी संपत्ति ChatsViewControllerके रूप में: var chats: [Chat] { return account.chats }
ma11hew28

जवाबों:


72

स्विफ्ट में संरचनाएं मूल्य द्वारा पारित की जाती हैं, लेकिन आप inoutअपने सरणी को संशोधित करने के लिए संशोधक का उपयोग कर सकते हैं (नीचे उत्तर देखें)। कक्षाएं संदर्भ से पारित की जाती हैं। Arrayऔर Dictionaryस्विफ्ट में स्ट्रक्चर्स के रूप में लागू किया गया है।


2
ऐरे को स्विफ्ट में मूल्य द्वारा कॉपी / पास नहीं किया जाता है - यह स्विफ्ट में नियमित संरचना की तुलना में बहुत अलग व्यवहार है। देखें stackoverflow.com/questions/24450284/...
बून

14
@ बून एरे अभी भी शब्दार्थ से कॉपी / पास-बाय-वैल्यू है, लेकिन सिर्फ गाय का उपयोग करने के लिए अनुकूलित है ।
eonil

4
और NSArrayक्योंकि NSArrayऔर स्विफ्ट सरणी में सूक्ष्म अर्थ अंतर (जैसे संदर्भ-प्रकार) हैं, और संभवतः संभवतः आपको अधिक बगों तक ले जाने की सलाह दी जाती है ।
eonil

1
यह मुझे गंभीर रूप से मार रहा था। मैं अपना सिर पीट रहा था कि चीजें काम क्यों नहीं कर रही हैं।
ख़ुशनशान

2
क्या होगा अगर inoutस्ट्रक्चर्स के साथ प्रयोग किया जाए?
एलस्टन

137

समारोह पैरामीटर ऑपरेटर के लिए हम का उपयोग करें:

चलो (यह डिफ़ॉल्ट रूप ऑपरेटर है, इसलिए हम छोड़ सकते हैं करते हैं ) एक पैरामीटर निरंतर (इसका मतलब है कि हम भी स्थानीय प्रतिलिपि संशोधित नहीं कर सकते) बनाने के लिए; इसे परिवर्तनशील बनाने के लिए

var (हम इसे स्थानीय रूप से संशोधित कर सकते हैं, लेकिन यह उस बाहरी चर को प्रभावित नहीं करेगा जो फ़ंक्शन को पारित कर दिया गया है); और इन-आउट पैरामीटर बनाने के लिए

इनऑउट करें। इन-आउट का अर्थ वास्तव में संदर्भ द्वारा परिवर्तनशील चर है, मूल्य से नहीं। और यह न केवल आवश्यकता है, संदर्भ द्वारा मान को स्वीकार भी द्वारा करने के लिए, संदर्भ द्वारा इसे पारित करने के तो साथ इसे पारित और - foo(&myVar)बस के बजायfoo(myVar)

तो इसे इस तरह से करें:

var arr = [1, 2, 3]

func addItem(inout localArr: [Int]) {
    localArr.append(4)
}

addItem(&arr)    
println(arr) // it will print [1, 2, 3, 4]

सटीक होने के लिए यह केवल एक संदर्भ नहीं है, बल्कि बाहरी चर के लिए एक वास्तविक उपनाम है, इसलिए आप किसी भी चर प्रकार के साथ ऐसा कर सकते हैं, उदाहरण के लिए पूर्णांक के साथ (आप इसे नया मान दे सकते हैं), हालांकि यह एक नहीं हो सकता है अच्छा अभ्यास और यह इस तरह से आदिम डेटा प्रकार को संशोधित करने के लिए भ्रामक हो सकता है।


11
यह वास्तव में यह नहीं समझाता है कि सरणी का उपयोग कैसे करें उदाहरण के लिए चर जिसे कॉपी नहीं किया गया है।
मतज उकमार

2
मैंने सोचा कि इन्टू ने एक गेटर और एक सेटर का उपयोग करके एक अस्थायी अस्थायी सरणी को कॉपी किया और फिर इसे फंक्शन से बाहर के रास्ते पर रीसेट कर दिया - यानी यह कॉपी किया गया
dumbledad

2
वास्तव में इन-आउट मूल्य परिणाम द्वारा कॉपी-आउट कॉपी या कॉल का उपयोग करता है। हालाँकि, एक अनुकूलन के रूप में इसका उपयोग संदर्भ द्वारा किया जा सकता है। "अनुकूलन के रूप में, जब तर्क स्मृति में एक भौतिक पते पर संग्रहीत मान होता है, तो फ़ंक्शन बॉडी के अंदर और बाहर दोनों में एक ही मेमोरी लोकेशन का उपयोग किया जाता है। अनुकूलित व्यवहार को संदर्भ द्वारा कॉल के रूप में जाना जाता है; यह सभी आवश्यकताओं को पूरा करता है। नकल के ओवरहेड को हटाते समय कॉपी-इन-कॉपी मॉडल। "
टॉड कनिंघम

11
स्विफ्ट 3 में, inoutस्थिति बदल गई है, यानीfunc addItem(localArr: inout [Int])
elquimista

3
इसके अलावा, varफ़ंक्शन पैरामीटर विशेषता के लिए अब उपलब्ध नहीं है।
एलक्विमिस्टा

23

अपने आप को परिभाषित करें BoxedArray<T>कि Arrayइंटरफ़ेस को लागू करता है लेकिन संग्रहीत कार्यों के सभी कार्यों को दर्शाता है। जैसे की

class BoxedArray<T> : MutableCollection, Reflectable, ... {
  var array : Array<T>

  // ...

  subscript (index: Int) -> T { 
    get { return array[index] }
    set(newValue) { array[index] = newValue }
  }
}

का प्रयोग करें BoxedArrayकहीं भी आप एक का उपयोग करेंगे Array। की एक नियत BoxedArrayसंदर्भ द्वारा हो जाएगा, यह एक वर्ग है, और इस तरह के माध्यम से संग्रहीत संपत्ति को बदलता है, Arrayइंटरफेस, सभी संदर्भों को दिखाई जाएगी।


थोड़ा डरावना समाधान :) - बिल्कुल सुरुचिपूर्ण नहीं - लेकिन ऐसा लगता है कि यह काम करेगा।
मतज उकमार

खैर, यह निश्चित है कि 'संदर्भ अर्थविज्ञान द्वारा पास' प्राप्त करने के लिए 'एनएसएरे का उपयोग करें' पर वापस गिरने से बेहतर है!
गोजनर

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

मैं सहमत हूँ। वहाँ भी अमूर्त है जहाँ BUT Stringका एक उपप्रकार है Anyयदि आप import Foundationतब का Stringउपप्रकार बन जाते हैं AnyObject
GoZoner

19

स्विफ्ट संस्करण 3-4 (XCode 8-9) के लिए, उपयोग करें

var arr = [1, 2, 3]

func addItem(_ localArr: inout [Int]) {
    localArr.append(4)
}

addItem(&arr)
print(arr)

3

कुछ इस तरह

var a : Int[] = []
func test(inout b : Int[]) {
    b += [1,2,3,4,5]
}
test(&a)
println(a)

???


3
मुझे लगता है कि सवाल एक साधन के लिए पूछ रहा है कि दो अलग-अलग वस्तुओं के गुण समान सरणी को इंगित करते हैं। अगर ऐसा है, तो कान का जवाब सही है: किसी को या तो श्रेणी में सरणी लपेटनी चाहिए, या NSArray का उपयोग करना चाहिए।
वेस कैंपेन

1
राइट, इनऑट केवल फ़ंक्शन बॉडी के जीवनकाल के लिए काम करता है (कोई करीबी व्यवहार नहीं)
क्रिश्चियन डिट्रिच

माइनर नाइट: यह func test(b: inout [Int])... शायद यह एक पुराना वाक्यविन्यास है; मैं केवल २०१६ में स्विफ्ट में आया था और यह उत्तर २०१४ से है इसलिए शायद चीजें अलग हुआ करती थीं?
रे तोल

2

एक अन्य विकल्प यह है कि एरे के उपभोक्ता से उसके मालिक को आवश्यकतानुसार इसके बारे में पूछा जाए। उदाहरण के लिए, कुछ की तर्ज पर:

class Account {
    var chats : [String]!
    var chatsViewController : ChatsViewController!

    func InitViewController() {
        chatsViewController.getChats = { return self.chats }
    }

}

class ChatsViewController {
    var getChats: (() -> ([String]))!

    func doSomethingWithChats() {
        let chats = getChats()
        // use it as needed
    }
}

फिर आप सरणी को संशोधित कर सकते हैं जितना आपको खाता वर्ग के अंदर पसंद है। ध्यान दें कि यह आपकी मदद नहीं करता है यदि आप व्यू कंट्रोलर क्लास से सरणी को संशोधित करना चाहते हैं।


0

उपयोग करना inoutएक समाधान है लेकिन यह मेरे लिए बहुत स्वादिस्ट नहीं लगता क्योंकि सरणियाँ मान प्रकार की होती हैं। Stylistically मैं व्यक्तिगत रूप से एक उत्परिवर्तित प्रति वापस करना चाहता हूँ:

func doSomething(to arr: [Int]) -> [Int] {
    var arr = arr
    arr.append(3) // or likely some more complex operation
    return arr
}

var ids = [1, 2]
ids = doSomething(to: ids)
print(ids) // [1,2,3]

1
इस तरह की चीज़ के लिए एक प्रदर्शन नकारात्मक पक्ष है। यह मूल सरणी को संशोधित करने के लिए टैड बिट कम फोन बैटरी का उपयोग करता है :)
डेविड रेक्टर

मैं आदरपूर्वक असहमत हूं। इस मामले में कॉल साइट पर पठनीयता आम तौर पर प्रदर्शन हिट को प्रभावित करती है। अपरिवर्तनीय कोड से शुरू करें और फिर बाद में इसे परिवर्तनशील बनाकर अनुकूलित करें। बड़े पैमाने पर सरणियों के मामले हैं जहां आप सही हैं लेकिन अधिकांश ऐप में 0.01% बढ़त का मामला है।
टोड्डा

1
मैं नहीं जानता कि आप किस बात से असहमत हैं। सरणी को कॉपी करने के लिए एक प्रदर्शन जुर्माना है और कम प्रदर्शन संचालन अधिक सीपीयू और इसलिए अधिक बैटरी का उपयोग करते हैं। मुझे लगता है कि आपने मान लिया था कि मैं कह रहा था कि यह एक बेहतर समाधान है, जो मैं नहीं था। मैं यह सुनिश्चित कर रहा था कि लोगों को एक सूचित विकल्प बनाने के लिए सभी जानकारी उपलब्ध हो।
डेविड रेक्टर

1
हाँ, तुम सही हो, कोई सवाल नहीं है अधिक कुशल है। मुझे लगा कि आप सुझाव दे रहे हैं कि inoutयह सार्वभौमिक रूप से बेहतर है क्योंकि यह बैटरी बचाता है। जिसके लिए मैं कहूंगा कि इस समाधान की पठनीयता, अपरिवर्तनीयता, और थ्रेड सुरक्षा सार्वभौमिक रूप से बेहतर है और यह इनऑउट केवल उन दुर्लभ मामलों में एक अनुकूलन के रूप में उपयोग किया जाना चाहिए जहां उपयोग केस इसे वारंट करता है।
टोड्डा

0

एक NSMutableArrayया एक का उपयोग करें NSArray, जो वर्ग हैं

इस तरह आपको किसी रैपर को फंसाने की जरूरत नहीं है और बिल्ड का उपयोग ब्रिजिंग में किया जा सकता है

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