टाइप-इन लूप के लिए कास्टिंग


116

मेरे पास इसके लिए लूप है:

for button in view.subviews {
}

अब मैं चाहता हूं कि बटन को एक कस्टम वर्ग में डाला जाए ताकि मैं इसके गुणों का उपयोग कर सकूं।

मैंने यह कोशिश की: for button in view.subviews as AClass

लेकिन यह काम नहीं करता है और मुझे एक त्रुटि देता है:'AClass' does not conform to protocol 'SequenceType'

और मैंने यह कोशिश की: for button:AClass in view.subviews

लेकिन न तो वह काम करता है।


कैसे के बारे मेंfor button in view.subviews as [AClass]
टीका

2
हाहा, मैं उस के बारे में सोचता था, निश्चित रूप से सरणी को AClass की श्रेणी में डालना बेहतर है, धन्यवाद आदमी। आप इसके बारे में एक उत्तर दे सकते हैं ताकि मैं आपको कुछ प्रतिनिधि दे
सकूं

जवाबों:


173

के लिए स्विफ्ट 2 और बाद में:

स्विफ्ट 2 कहते मामले पैटर्न के लिए छोरों, जो इसे और भी आसान और सुरक्षित एक में डाली टाइप करने के लिए बनाता है के लिए पाश:

for case let button as AClass in view.subviews {
    // do something with button
}

यह स्विफ्ट 1.2 और उससे पहले के मुकाबले आप क्यों बेहतर कर सकते हैं ? क्योंकि केस पैटर्न आपको अपने विशिष्ट प्रकार को संग्रह से बाहर निकालने की अनुमति देता है। यह केवल उस प्रकार से मेल खाता है जिसे आप खोज रहे हैं, इसलिए यदि आपके सरणी में मिश्रण है, तो आप केवल एक विशिष्ट प्रकार पर काम कर सकते हैं।

उदाहरण के लिए:

let array: [Any] = [1, 1.2, "Hello", true, [1, 2, 3], "World!"]
for case let str as String in array {
    print(str)
}

आउटपुट:

Hello
World!

के लिए स्विफ्ट 1.2 :

इस स्थिति में, आप कास्टिंग कर रहे हैं view.subviewsऔर नहीं button, इसलिए आपको इसे अपने इच्छित प्रकार के सरणी में नीचे करने की आवश्यकता है:

for button in view.subviews as! [AClass] {
    // do something with button
}

नोट: यदि अंतर्निहित सरणी प्रकार नहीं है [AClass], तो यह क्रैश हो जाएगा। यही कारण है कि है !पर as!आपको बता रहा है। यदि आप इस प्रकार के बारे में निश्चित नहीं हैं, तो आप as?वैकल्पिक बाध्यकारी के साथ एक सशर्त डाली का उपयोग कर सकते हैं if let:

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    for button in subviews {
        // do something with button
    }
}

के लिए स्विफ्ट 1.1 और पूर्ववर्ती संस्करण:

for button in view.subviews as [AClass] {
    // do something with button
}

नोट: यदि सबकुछ प्रकार के नहीं हैं तो यह भी दुर्घटनाग्रस्त हो जाएगा AClass। ऊपर सूचीबद्ध सुरक्षित विधि स्विफ्ट के पुराने संस्करणों के साथ भी काम करती है।


बस मेरे जैसे अन्य लोगों के लिए एक नोट जो पहले नहीं मिला था - वर्ग का नाम [ ]इस उदाहरण में बिल्कुल कोष्ठक के अंदर जाना है । शायद यह सिर्फ मुझे है, लेकिन मुझे लगा कि यह पहली बार कोड नमूने में सिर्फ एक स्वरूपण पसंद था :) मुझे लगता है कि यह है क्योंकि हम एक सरणी के लिए कास्टिंग कर रहे हैं।

@kmcgrady इसकी [Class]तुलना में यह बहुत बेहतर है Array<Class>
आर्बिटुर जूल

तो जिज्ञासा से बाहर, लूप के लिए कई केस स्टेटमेंट करने का एक तरीका है? ईजी अगर मैं बटन के लिए एक काम करना चाहता हूं, तो पाठ फ़ील्ड में दूसरा?
RonLugge

125

यह विकल्प अधिक सुरक्षित है:

for case let button as AClass in view.subviews {
}

या घूमने का तरीका:

view.subviews
  .compactMap { $0 as AClass }
  .forEach { .... }

1
यह एक अच्छा जवाब है क्योंकि कोई बल नहीं है।
पैट्रिक

1
यह स्वीकृत उत्तर होना चाहिए। सबसे अच्छा एक और सही एक है!
थॉम्सो कैलमोन

सही उत्तर। छोटा और सरल।
पाषाण

4

आप एक whereक्लॉज का उपयोग भी कर सकते हैं

for button in view.subviews where button is UIButton {
    ...
}

12
जहां क्लॉज एक बूलियन गार्ड है, लेकिन buttonलूप बॉडी के अंदर के प्रकार को कास्ट नहीं करता है, जो अन्य समाधानों का लक्ष्य है। तो यह केवल उन तत्वों पर लूप बॉडी चलाएगा view.subviewsजो UIButtonएस हैं, लेकिन कॉलिंग AClass-सीपीक तरीकों पर उदाहरण के लिए मदद नहीं करता है button
जॉन व्हिटले

1
@ जॉनोहली आप सही हैं कि whereकेवल गार्ड और कास्ट नहीं है।
edelaney05

whereमामलों के लिए और अधिक सुरुचिपूर्ण और पठनीय हो सकता है (सजा अनजाने में) जहां आपको केवल बूलियन गार्ड की आवश्यकता होती है।
एसटीओ

3

प्रदान किए गए उत्तर सही हैं, मैं इसे जोड़ना चाहता था।

बल कास्टिंग के साथ लूप के लिए उपयोग करते समय, कोड क्रैश हो जाएगा (जैसा कि पहले ही दूसरों द्वारा उल्लेख किया गया है)।

for button in view.subviews as! [AClass] {
    // do something with button
}

लेकिन इसके बजाय अगर-क्लॉज का उपयोग किया जाता है,

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    ...
}

एक और तरीका है एक लूप का उपयोग करना है:

/* If you need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let (index, subview) = iterator.next() as? (Int, AClass) {
    // Use the subview
    // ...
}

/* If you don't need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let subview = iterator.next().element as? AClass {
    // Use the subview
    // ...
}

यदि सरणी के कुछ तत्व (लेकिन सभी नहीं) प्रकार के हो सकते हैं तो यह अधिक सुविधाजनक लगता है AClass

हालांकि अभी (स्विफ्ट 5 के रूप में), मैं फॉर-केस लूप के लिए जाऊंगा:

for case let (index, subview as AClass) in view.subviews.enumerated() {
    // ...
}

for case let subview as AClass in view.subviews {
    // ...
}

यहाँ सिर्फ एक ही संदेह ... क्या स्विफ्ट एनुमरेटेड फ़ंक्शन यहाँ पुनरावृत्तियों / पाश प्रदर्शन करता है .. बस प्रदर्शन खोने के लिए सोच विचार करना महान नहीं होगा ... धन्यवाद
एम्बर

2

वैवामा द्वारा प्रदान किया गया उत्तर स्विफ्ट 1.0 में सही था। और अब स्विफ्ट 2.0 के साथ काम नहीं करता है।

यदि आप कोशिश करते हैं, तो आपको एक त्रुटि मिलेगी:

'[AnyObject]' '[AClass]' के लिए परिवर्तनीय नहीं है;

स्विफ्ट 2.0 में आपको इस तरह लिखना होगा:

for button in view.subviews as! [AClass]
{
}

0

आप कास्टिंग कर सकते हैं और इसके साथ ही सुरक्षित रह सकते हैं:

for button in view.subviews.compactMap({ $0 as? AClass }) {

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