स्विफ्ट क्लास आत्मनिरीक्षण और जेनरिक


121

मैं classजेनेरिक का उपयोग करके एक उदाहरण आधारित प्रकार को गतिशील रूप से बनाने की कोशिश कर रहा हूं , हालांकि मैं कक्षा आत्मनिरीक्षण के साथ कठिनाई का सामना कर रहा हूं।

यहाँ प्रश्न हैं:

  • क्या एक स्विफ्ट-ओब्ज-सी के बराबर है self.class?
  • वहाँ एक वर्ग से AnyClassपरिणाम का उपयोग कर तुरंत करने के लिए एक रास्ता है NSClassFromString?
  • क्या AnyClassसामान्य पैरामीटर से सख्ती से जानकारी प्राप्त करने या अन्यथा टाइप करने का कोई तरीका है T? (सी # typeof(T)सिंटैक्स के समान)

2
stackoverflow.com/a/24069875/292145 स्विफ्ट प्रतिबिंब एपीआई पर कुछ संकेत देता है।
कलस

5
ऑब्जेक्टिव-सी , स्विफ्ट I विश्वास में self.classबन जाएगाself.dynamicType.self
फिलिप हरमन

1
एक उदाहरण विधि में, यहां बताया गया है कि क्लास विधि कैसे कहें:self.dynamicType.foo()

जवाबों:


109

खैर, एक के लिए, स्विफ्ट बराबर [NSString class]है .self( मेटाटाइप डॉक्स देखें , हालांकि वे बहुत पतले हैं)।

वास्तव में, NSString.classकाम भी नहीं करता है! आपको उपयोग करना होगा NSString.self

let s = NSString.self
var str = s()
str = "asdf"

इसी तरह, एक तेज वर्ग के साथ मैंने कोशिश की ...

class MyClass {

}

let MyClassRef = MyClass.self

// ERROR :(
let my_obj = MyClassRef()

हम्म ... त्रुटि कहती है:

खेल का मैदान निष्पादन में विफल रहा: त्रुटि:: 16: 1: त्रुटि: एक मेटाटाइप मान के साथ वर्ग प्रकार 'एक्स' के एक ऑब्जेक्ट का निर्माण करने के लिए '@required' इनिशियलाइज़र की आवश्यकता होती है

 Y().me()
 ^
 <REPL>:3:7: note: selected implicit initializer with type '()'
 class X {
       ^

मुझे यह पता लगाने में थोड़ा समय लगा कि इसका क्या अर्थ है ... यह पता चलता है कि वर्ग ए को चाहता है @required init()

class X {
    func me() {
        println("asdf")
    }

    required init () {

    }
}

let Y = X.self

// prints "asdf"
Y().me()

कुछ डॉक्स इसका उल्लेख करते हैं .Type, लेकिन MyClass.Typeमुझे खेल के मैदान में एक त्रुटि देता है।


1
Metatype डॉक्स के लिए आपके लिंक के लिए धन्यवाद! मैंने पूरी तरह से उस पहलू को अनदेखा कर दिया, दोह!
एरिक

14
आप उपयोग कर सकते हैं .Typeया .Protocolचर घोषणा में, उदाहरण के लिएlet myObject: MyObject.Type = MyObject.self
सुल्तान

1
सुल्तान: तो MyObject.Type एक घोषणा है लेकिन MyObject.self एक फ़ैक्टरी विधि है (जिसे कहा जा सकता है) और myObject एक वैरिएबल है जिसमें फ़ैक्टरी विधि का संदर्भ होता है। कॉल myObject () वर्ग MyObject का एक उदाहरण उत्पन्न करेगा। यह बेहतर उदाहरण होगा यदि myObject वैरिएबल का नाम myObjectFactory था?
बूटीच

2
@पहले requiredहटा दिया जाना चाहिए
fujianjin6471

49

यहाँ कैसे उपयोग करने के लिए है NSClassFromString। आपको यह जानना होगा कि आप किसके साथ क्या करने जा रहे हैं। यहाँ एक सुपरक्लास-उपवर्ग जोड़ी है जो अपने लिए खुद का वर्णन करना जानते हैं println:

@objc(Zilk) class Zilk : NSObject {
    override var description : String {return "I am a Zilk"}
}

@objc(Zork) class Zork : Zilk {
    override var description : String {return "I am a Zork"}
}

@objइन वर्गों के उद्देश्य-सी मुंगेड नाम को निर्धारित करने के लिए विशेष वाक्यविन्यास के उपयोग पर ध्यान दें ; यह महत्वपूर्ण है, क्योंकि अन्यथा हम मुंग्ड स्ट्रिंग को नहीं जानते हैं जो प्रत्येक वर्ग को नामित करता है।

अब हम NSClassFromStringZork क्लास या Zilk क्लास बनाने के लिए उपयोग कर सकते हैं , क्योंकि हम जानते हैं कि हम इसे NSObject के रूप में टाइप कर सकते हैं और बाद में क्रैश नहीं कर सकते:

let aClass = NSClassFromString("Zork") as NSObject.Type
let anObject = aClass()
println(anObject) // "I am a Zork"

और यह प्रतिवर्ती है; println(NSStringFromClass(anObject.dynamicType))भी काम करता है।


आधुनिक संस्करण:

    if let aClass = NSClassFromString("Zork") as? NSObject.Type {
        let anObject = aClass.init()
        print(anObject) // "I am a Zork"
        print(NSStringFromClass(type(of:anObject))) // Zork
    }

10
@objc(ClassName)बिट के लिए अपवोट करें । मुझे @objcविशेषता के बारे में पता था लेकिन यह नहीं कि आप वर्ग के नाम के बारे में संकेत भी दे सकते हैं।
एरिक

1
उत्कृष्ट समाधान जो अभी भी कम या ज्यादा 6 वर्षों में लिखित रूप में काम करता है। बस एक युगल नाबालिग खेल के मैदान के लिए पूछता है: as! NSObject.Typeपहली पंक्ति aClass.init()में और दूसरी
काजी

13

यदि मैं दस्तावेज़ीकरण सही पढ़ रहा हूं, यदि आप उदाहरणों से निपटते हैं और उदाहरण के लिए उसी प्रकार का एक नया उदाहरण वापस करना चाहते हैं जो आपके द्वारा दी गई वस्तु से है और प्रकार का निर्माण एक init () के साथ किया जा सकता है:

let typeOfObject = aGivenObject.dynamicType
var freshInstance = typeOfObject()

मैंने जल्दी से स्ट्रिंग के साथ इसका परीक्षण किया:

let someType = "Fooo".dynamicType
let emptyString = someType()
let threeString = someType("Three")

जो ठीक काम किया।


1
हां, dynamicTypeजैसा कि मुझे उम्मीद थी कि काम करता है। हालांकि, मैं प्रकारों की तुलना करने में असमर्थ रहा हूं। असली बड़ा उपयोग जेनेरिक के साथ है, इसलिए मुझे कुछ पसंद हो सकता है Generic<T>और अंदर if T is Double {...}। ऐसा लगता है कि दुर्भाग्य से संभव नहीं है।
एरिक

1
@ साइलो क्या आपको कभी सामान्य तौर पर यह पूछने का कोई तरीका मिला कि क्या दो वस्तुएं एक ही वर्ग की हैं?
मैट

1
@ मैट एलिगेंटली नहीं, नहीं मैंने नहीं किया। हालांकि, मैं एक बनाने के लिए कर रहा था Defaultableप्रोटोकॉल है जो सी # के लिए इसी तरह की काम करता है defaultजैसे प्रकार के लिए कीवर्ड और उचित एक्सटेंशन Stringऔर Int। के सामान्य अवरोध को जोड़कर T:Defaultable, मैं जांच कर सकता था कि क्या तर्क पारित हुआ is T.default()
एरिक

1
@ साइलो चतुर; मुझे वह कोड देखना है! मुझे लगता है कि यह "है" के उपयोग पर अजीब सीमाओं के आसपास हो जाता है। मैंने उन सीमाओं पर बग दर्ज किया है, और वर्ग आत्मनिरीक्षण के सामान्य अभाव पर भी। मैंने NSStringFromClass का उपयोग करते हुए तारों की तुलना करना समाप्त कर दिया, लेकिन निश्चित रूप से यह केवल NSObject वंशजों के लिए काम करता है।
मैट

1
@matt दुर्भाग्य से यह वास्तव में की तुलना में अधिक चतुर लगता है क्योंकि आपको अभी भी करना है value is String.default()... आदि, जिसे आप केवल value is Stringइसके बजाय करना समाप्त करेंगे ।
एरिक

13

में तेजी से 3

object.dynamicType

पदावनत किया गया है।

इसके बजाय उपयोग करें:

type(of:object)

7

तुलना प्रकारों का स्विफ्ट कार्यान्वयन

protocol Decoratable{}
class A:Decoratable{}
class B:Decoratable{}
let object:AnyObject = A()
object.dynamicType is A.Type//true
object.dynamicType is B.Type//false
object.dynamicType is Decoratable.Type//true

नोट: ध्यान दें कि यह प्रोटोकॉल के साथ भी काम करता है, वस्तु का विस्तार हो भी सकता है और नहीं भी


1

अंत में काम करने के लिए कुछ मिला। यह थोड़ा आलसी है, लेकिन यहां तक ​​कि NSClassFromString () मार्ग ने मेरे लिए काम नहीं किया ...

import Foundation

var classMap = Dictionary<String, AnyObject>()

func mapClass(name: String, constructor: AnyObject) -> ()
{
    classMap[name] = constructor;
}

class Factory
{
    class func create(className: String) -> AnyObject?
    {
        var something : AnyObject?

        var template : FactoryObject? = classMap[className] as? FactoryObject

        if (template)
        {
            let somethingElse : FactoryObject = template!.dynamicType()

            return somethingElse
        }

        return nil
    }
}


 import ObjectiveC

 class FactoryObject : NSObject
{
    @required init() {}
//...
}

class Foo : FactoryObject
{
    class override func initialize()
    {
        mapClass("LocalData", LocalData())
    }
    init () { super.init() }
}

var makeFoo : AnyObject? = Factory.create("Foo")

और बिंगो, "मेकफू" में एक फू उदाहरण है।

नकारात्मक पक्ष यह है कि आपके वर्ग को FactoryObject से निष्क्रिय होना चाहिए और उनके पास Obj-C + initialize पद्धति होनी चाहिए ताकि आपकी कक्षा वैश्विक फ़ंक्शन "mapClass" द्वारा स्वचालित रूप से कक्षा के मानचित्र में सम्मिलित हो जाए।


1

यहाँ एक और उदाहरण है जो वर्ग पदानुक्रम कार्यान्वयन दिखा रहा है, जो स्वीकृत उत्तर के समान है, स्विफ्ट की पहली रिलीज़ के लिए अद्यतन किया गया है।

class NamedItem : NSObject {
    func display() {
        println("display")
    }

    required override init() {
        super.init()
        println("base")
    }
}

class File : NamedItem {
    required init() {
        super.init()
        println("folder")
    }
}

class Folder : NamedItem {
    required init() {
        super.init()
        println("file")
    }
}

let y = Folder.self
y().display()
let z = File.self
z().display()

इस परिणाम को प्रिंट करता है:

base
file
display
base
folder
display

2
यदि चर सुपरक्लॉस का प्रकार है तो यह तकनीक सही तरीके से काम नहीं करती है। उदाहरण के लिए, दिया गया है var x: NamedItem.Type, अगर मैं इसे असाइन करता हूं x = Folder.Type, तो x()एक नया रिटर्न देता है NamedItem, न कि एक Folder। यह कई अनुप्रयोगों के लिए तकनीक को बेकार कर देता है। मैं इसे एक बग मानता हूं ।
फतमान

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