वस्तुओं का एक निश्चित आकार का सरणी कैसे बनाएं


102

स्विफ्ट में, मैं 64 SKSpriteNode की एक सरणी बनाने की कोशिश कर रहा हूं। मैं पहले इसे खाली करना चाहता हूं, फिर मैं स्प्राइट्स को पहली 16 कोशिकाओं में और आखिरी 16 कोशिकाओं (एक शतरंज के खेल का अनुकरण) में डालूंगा।

डॉक में जो मुझे समझ में आया, उससे मुझे कुछ उम्मीद होगी:

var sprites = SKSpriteNode()[64];

या

var sprites4 : SKSpriteNode[64];

लेकिन यह काम नहीं करता है। दूसरे मामले में, मुझे यह कहते हुए एक त्रुटि मिलती है: "फिक्स्ड-लेंथ एरेज़ अभी तक समर्थित नहीं हैं"। क्या यह वास्तविक हो सकता है? मेरे लिए यह एक बुनियादी विशेषता की तरह लगता है। मुझे उनके सूचकांक द्वारा सीधे तत्व तक पहुंचने की आवश्यकता है।

जवाबों:


150

निश्चित-लंबाई सरणियों का अभी तक समर्थन नहीं किया गया है। वास्तव में इसका क्या मतलब है? ऐसा नहीं है कि आप nकई चीजों की एक सरणी नहीं बना सकते हैं - जाहिर है आप सिर्फ let a = [ 1, 2, 3 ]तीन Intएस की एक सरणी प्राप्त करने के लिए कर सकते हैं । इसका सीधा सा मतलब है कि सरणी का आकार कुछ ऐसा नहीं है जिसे आप टाइप जानकारी के रूप में घोषित कर सकते हैं

यदि आप एक सरणी चाहते हैं nil, तो आपको पहले एक वैकल्पिक प्रकार की एक सरणी की आवश्यकता होगी - यदि [SKSpriteNode?]नहीं [SKSpriteNode]- यदि आप गैर-वैकल्पिक प्रकार का एक चर घोषित करते हैं, चाहे वह एक सरणी हो या एकल मूल्य हो, यह नहीं हो सकता है nil। (यह भी ध्यान दें कि आप [SKSpriteNode?]से अलग है [SKSpriteNode]?... आप वैकल्पिक सरणी चाहते हैं, वैकल्पिक सरणी नहीं।)

स्विफ्ट को डिज़ाइन करने के बारे में बहुत स्पष्ट है कि चरों को आरंभीकृत करने की आवश्यकता है, क्योंकि असंबद्ध संदर्भों की सामग्री के बारे में धारणाएं उन तरीकों में से एक हैं जो सी (और कुछ अन्य भाषाओं) में कार्यक्रम छोटी हो सकती हैं। तो, आपको [SKSpriteNode?]64 nilएस वाले एक सरणी के लिए स्पष्ट रूप से पूछना होगा :

var sprites = [SKSpriteNode?](repeating: nil, count: 64)

यह वास्तव में [SKSpriteNode?]?, हालांकि, वैकल्पिक स्प्राइट का एक वैकल्पिक सरणी देता है। (थोड़ा अजीब है, क्योंकि init(count:,repeatedValue:)शून्य को वापस करने में सक्षम नहीं होना चाहिए।) सरणी के साथ काम करने के लिए, आपको इसे खोलना होगा। ऐसा करने के कुछ तरीके हैं, लेकिन इस मामले में मैं वैकल्पिक बाध्यकारी सिंटैक्स का पक्ष लूंगा:

if var sprites = [SKSpriteNode?](repeating: nil, count: 64){
    sprites[0] = pawnSprite
}

धन्यवाद, मैंने कोशिश की थी कि एक, लेकिन मैं "भूल गया था?"। हालाँकि, मैं अभी भी मूल्य बदलने में असमर्थ हूँ? मैंने दोनों की कोशिश की: 1) स्प्राइट्स [0] = स्प्राइटपॉइन और 2) स्प्राइट्स.इन्टर (स्प्राइटपॉइंट, एटइंडेक्स: 0)।
हेनरी लापिएरे

1
आश्चर्य! spritesअपने अनुमानित प्रकार को देखने के लिए अपने संपादक / खेल के मैदान में सेमी-क्लिक करें - यह वास्तव में है SKSpriteNode?[]?: वैकल्पिक स्प्राइट का एक वैकल्पिक सरणी। आप एक वैकल्पिक को सब्सक्राइब नहीं कर सकते हैं, इसलिए आपको इसे खोलना होगा ... संपादित उत्तर देखें।
रिकस्टर

यह वास्तव में काफी अजीब है। जैसा कि आपने उल्लेख किया है, मुझे नहीं लगता कि सरणी वैकल्पिक होनी चाहिए, क्योंकि हमने इसे स्पष्ट रूप से परिभाषित किया है? [] और नहीं? [] हर बार जब मुझे इसकी आवश्यकता होती है, तो इसे बंद करने के लिए परेशान करने की तरह। किसी भी स्थिति में, यह काम करने लगता है: var sprites = SKSpriteNode? [] (गिनती: 64, दोहरायावैल्यू: nil); अगर var undrappedSprite = sprites {unwrappedSprite [0] = spritePawn; }
हेनरी लापिएरे

सिंटैक्स 3 और 4 के लिए बदल गया है, कृपया नीचे दिए गए अन्य उत्तर देखें
क्रशालोट

62

अब आप जो करने जा रहे हैं, वह एक प्रारंभिक गिनती के साथ एक सरणी बनाने के लिए है जो दोहराता है:

var sprites = [SKSpriteNode?](count: 64, repeatedValue: nil)

फिर आप जो चाहें मान भर सकते हैं।


में स्विफ्ट 3.0 :

var sprites = [SKSpriteNode?](repeating: nil, count: 64)

5
क्या निश्चित आकार की एक सरणी घोषित करने का कोई तरीका है ?
ッ ク ア

2
@AlexanderSupertramp नहीं, एक सरणी के लिए एक आकार घोषित करने का कोई तरीका नहीं है
drewag

1
@ @ No ッ ク ス एक सरणी के लिए एक निश्चित आकार घोषित करने का कोई तरीका नहीं है, लेकिन आप निश्चित रूप से अपनी खुद की संरचना बना सकते हैं जो एक सरणी को लपेटता है जो एक निश्चित आकार को लागू करता है।
5

10

इस सवाल का जवाब पहले ही दिया जा चुका है, लेकिन स्विफ्ट 4 के समय की कुछ अतिरिक्त जानकारी के लिए:

प्रदर्शन के मामले में, आपको सरणी के लिए मेमोरी को आरक्षित करना चाहिए, गतिशील रूप से इसे बनाने के मामले में, जैसे तत्वों को जोड़ना Array.append()

var array = [SKSpriteNode]()
array.reserveCapacity(64)

for _ in 0..<64 {
    array.append(SKSpriteNode())
}

यदि आप जानते हैं कि आपके द्वारा इसमें जोड़े जाने वाले तत्वों की न्यूनतम राशि होगी, लेकिन अधिकतम राशि नहीं, तो आपको इसका उपयोग करना चाहिए array.reserveCapacity(minimumCapacity: 64)


6

एक खाली SKSpriteNode की घोषणा करें, ताकि अनचाहे की जरूरत न पड़े

var sprites = [SKSpriteNode](count: 64, repeatedValue: SKSpriteNode())

7
इससे सावधान रहें। यह उस ऑब्जेक्ट के एक ही उदाहरण के साथ एरे को भर देगा (एक अलग उदाहरण की उम्मीद कर सकता है)
एंडी हिन

ठीक है, लेकिन यह ओपी प्रश्न को हल करता है, साथ ही, यह जानते हुए कि सरणी एक ही उदाहरण ऑब्जेक्ट से भरी हुई है, तो आपको इसके साथ निपटना होगा, कोई अपराध नहीं।
कार्लोस। वी।

5

अभी के लिए, शब्दार्थ रूप से निकटतम एक निश्चित तत्वों के साथ एक टपल होगा।

typealias buffer = (
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode)

लेकिन यह (1) उपयोग करने के लिए बहुत असहज है और (2) मेमोरी लेआउट अपरिभाषित है। (कम से कम मेरे लिए अज्ञात)


5

स्विफ्ट 4

आप इसके बारे में कुछ हद तक सरणी बनाम संदर्भ की सरणी के रूप में सोच सकते हैं।

  • [SKSpriteNode] वास्तविक वस्तुएं होनी चाहिए
  • [SKSpriteNode?] इसमें वस्तुओं का संदर्भ हो सकता है, या nil

उदाहरण

  1. 64 डिफ़ॉल्ट के साथ एक सरणी बनाना SKSpriteNode:

    var sprites = [SKSpriteNode](repeatElement(SKSpriteNode(texture: nil),
                                               count: 64))
  2. 64 खाली स्लॉट्स (उर्फ वैकल्पिक ) के साथ एक सरणी बनाना :

    var optionalSprites = [SKSpriteNode?](repeatElement(nil,
                                          count: 64))
  3. वस्तुओं (टूट का एक सरणी में optionals की एक सरणी परिवर्तित [SKSpriteNode?]में [SKSpriteNode]):

    let flatSprites = optionalSprites.flatMap { $0 }

    countजिसके परिणामस्वरूप flatSpritesमें वस्तुओं की गिनती पर निर्भर करता है optionalSprites: खाली optionals नजरअंदाज कर दिया जाएगा, यानी छोड़ दिया।


flatMapपदावनत किया जाता है, compactMapयदि संभव हो तो इसे अद्यतन किया जाना चाहिए । (मैं इस जवाब को संपादित नहीं कर सकता)
हेलोजो

1

यदि आप जो चाहते हैं वह एक निश्चित आकार की सरणी है, और इसे nilमानों के साथ प्रारंभ करें , आप इसके साथ UnsafeMutableBufferPointer64 नोड्स के लिए एक , आवंटित मेमोरी का उपयोग कर सकते हैं , और फिर पॉइंटर प्रकार के उदाहरण को सब्मिट करके / से मेमोरी में पढ़ / लिख सकते हैं। यह भी जाँच से बचने का लाभ है कि क्या स्मृति को पुनः स्थापित किया जाना चाहिए, जो Arrayकरता है। लेकिन मुझे आश्चर्य होगा कि यदि कंपाइलर उन सरणियों के लिए ऑप्टिमाइज़ नहीं करता है जिनके पास उन तरीकों के लिए कोई और कॉल नहीं है जिन्हें आकार देने की आवश्यकता हो सकती है, सृजन स्थल पर अन्य के अलावा।

let count = 64
let sprites = UnsafeMutableBufferPointer<SKSpriteNode>.allocate(capacity: count)

for i in 0..<count {
    sprites[i] = ...
}

for sprite in sprites {
    print(sprite!)
}

sprites.deallocate()

हालांकि यह बहुत उपयोगकर्ता के अनुकूल नहीं है। तो, चलो एक आवरण बनाते हैं!

class ConstantSizeArray<T>: ExpressibleByArrayLiteral {
    
    typealias ArrayLiteralElement = T
    
    private let memory: UnsafeMutableBufferPointer<T>
    
    public var count: Int {
        get {
            return memory.count
        }
    }
    
    private init(_ count: Int) {
        memory = UnsafeMutableBufferPointer.allocate(capacity: count)
    }
    
    public convenience init(count: Int, repeating value: T) {
        self.init(count)
        
        memory.initialize(repeating: value)
    }
    
    public required convenience init(arrayLiteral: ArrayLiteralElement...) {
        self.init(arrayLiteral.count)
        
        memory.initialize(from: arrayLiteral)
    }
    
    deinit {
        memory.deallocate()
    }
    
    public subscript(index: Int) -> T {
        set(value) {
            precondition((0...endIndex).contains(index))
            
            memory[index] = value;
        }
        get {
            precondition((0...endIndex).contains(index))
            
            return memory[index]
        }
    }
}

extension ConstantSizeArray: MutableCollection {
    public var startIndex: Int {
        return 0
    }
    
    public var endIndex: Int {
        return count - 1
    }
    
    func index(after i: Int) -> Int {
        return i + 1;
    }
}

अब, यह एक वर्ग है, और एक संरचना नहीं है, इसलिए यहां कुछ संदर्भ गिनती ओवरहेड है। आप इसे एक structबदले में बदल सकते हैं , लेकिन क्योंकि स्विफ्ट आपको कॉपी इनिशियलाइज़र और deinitसंरचनाओं पर उपयोग करने की क्षमता प्रदान नहीं करता है , तो आपको एक सौदा विधि की आवश्यकता होगी (func release() { memory.deallocate() } ) की , और संरचना के सभी कॉपी किए गए इंस्टेंसेस एक ही मेमोरी को संदर्भित करेंगे।

अब, यह वर्ग काफी अच्छा हो सकता है। इसका उपयोग सरल है:

let sprites = ConstantSizeArray<SKSpriteNode?>(count: 64, repeating: nil)

for i in 0..<sprites.count {
    sprite[i] = ...
}

for sprite in sprites {
    print(sprite!)
}

अनुरूपता को लागू करने के लिए अधिक प्रोटोकॉल के लिए, ऐरे प्रलेखन ( संबंधों पर स्क्रॉल करें ) देखें।


-3

एक चीज़ जो आप कर सकते हैं, वह है शब्दकोश बनाना। 64 तत्वों की तलाश में आपके विचार से थोड़ा मैला हो सकता है लेकिन यह काम पूरा करता है। मुझे यकीन नहीं है कि अगर इसका "पसंदीदा तरीका" है, लेकिन यह मेरे लिए काम करता है, तो मैं एक संरचना का उपयोग कर सकता हूं।

var tasks = [0:[forTasks](),1:[forTasks](),2:[forTasks](),3:[forTasks](),4:[forTasks](),5:[forTasks](),6:[forTasks]()]

2
यह सरणी से बेहतर कैसे है? मेरे लिए यह एक ऐसा हैक है जो समस्या का समाधान भी नहीं करता है: आप tasks[65] = fooइस मामले में और सवाल से सरणी के मामले में बहुत अच्छी तरह से कर सकते हैं ।
लाक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.