development

신속한 클래스 내부 검사 및 제네릭

big-blog 2020. 7. 19. 00:07
반응형

신속한 클래스 내부 검사 및 제네릭


class제네릭을 사용하여 인스턴스 기반 유형 을 동적으로 만들려고 하지만 클래스 내부 검사에 어려움이 있습니다.

질문은 다음과 같습니다.

  • Obj-C와 같은 Swift가 self.class있습니까?
  • AnyClass결과를 사용하여 클래스를 인스턴스화하는 방법이 NSClassFromString있습니까?
  • AnyClass일반 매개 변수에서 정보를 엄격하게 거나 입력 하는 방법이 T있습니까? (C #의 typeof(T)구문과 유사 )

글쎄, 스위프트와 동등한 [NSString class]것은 .self( Metatype docs 는 꽤 얇지 만 참조하십시오 ).

사실, 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 : 오류 : 메타 타입 값으로 클래스 유형 'X'의 객체를 구성하려면 '@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놀이터에서 오류가 발생합니다.


사용 방법은 다음과 같습니다 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이 클래스의 Objective-C munged 이름을 지시하기 위해 특수 구문을 사용하십시오 . 그렇지 않으면 각 클래스를 지정하는 녹은 문자열을 알지 못하기 때문에 중요합니다.

Now we can use NSClassFromString to make the Zork class or the Zilk class, because we know we can type it as an NSObject and not crash later:

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

And it's reversible; println(NSStringFromClass(anObject.dynamicType)) also works.


If I'm reading the documentation right, if you deal with instances and e.g. want to return a new instance of the same Type than the object you have been given and the Type can be constructed with an init() you can do:

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

I quickly tested it with String:

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

which worked fine.


In swift 3

object.dynamicType

is deprecated.

Instead use:

type(of:object)

Swift implementation of comparing types

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

NOTE: Notice that it also works with protocols the object may or may not extend


Finally got something to work. Its a bit lazy but even the NSClassFromString() route did not work for me...

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")

and bingo, "makeFoo" contains a Foo instance.

The downside is your classes must derrive from FactoryObject and they MUST have the Obj-C +initialize method so your class gets automagically inserted in the class map by global function "mapClass".


Here is another example showing class hierarchy implementation, similar to accepted answer, updated for the first release of Swift.

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()

Prints this result:

base
file
display
base
folder
display

참고URL : https://stackoverflow.com/questions/24049673/swift-class-introspection-generics

반응형