Swift 클래스 인트로 스펙 션 및 제네릭


121

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

질문은 다음과 같습니다.

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

2
stackoverflow.com/a/24069875/292145 는 Swift 리플렉션 API에 대한 몇 가지 힌트를 제공합니다.
Klaas

5
오브젝티브 C의의가 self.class될 것 self.dynamicType.self스위프트 I의 믿음
필립 HERMANS에게

1
인스턴스 메서드에서 클래스 메서드를 호출하는 방법은 다음과 같습니다.self.dynamicType.foo()

답변:


109

글쎄, 하나는 Swift와 동등한 것 [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놀이터에서 오류가 발생합니다.


1
Metatype 문서에 대한 링크를 주셔서 감사합니다! 나는 유형의 측면을 완전히 간과했습니다.
에릭

14
.Type또는 .Protocol변수 선언에서 사용할 수 있습니다 . 예 :let myObject: MyObject.Type = MyObject.self
Sulthan

1
Sulthan : MyObject.Type은 선언이지만 MyObject.self는 팩토리 메서드 (호출 가능)이고 myObject는 팩토리 메서드에 대한 참조를 포함하는 변수입니다. myObject () 호출은 MyObject 클래스의 인스턴스를 생성합니다. myObject 변수의 이름이 myObjectFactory?
bootchk

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구문을 사용하여 이러한 클래스의 Objective-C 뭉친 이름을 지정합니다. 그렇지 않으면 각 클래스를 지정하는 뭉친 문자열을 알지 못하기 때문에 중요합니다.

이제 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()두 번째 줄
Kaji

13

문서 권한을 읽고있는 경우 인스턴스를 처리하고 예를 들어 주어진 객체와 동일한 유형의 새 인스턴스를 반환하고 유형을 init ()로 구성 할 수있는 경우 다음을 수행 할 수 있습니다.

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

String으로 빠르게 테스트했습니다.

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

잘 작동했습니다.


1
네, dynamicType예상대로 작동합니다. 그러나 나는 유형을 비교할 수 없었습니다. 내가 좋아하는 뭔가를 할 수 있도록 실제 큰 사용은 제네릭 함께 Generic<T>내부를 if T is Double {...}. 불행히도 불가능한 것 같습니다.
Erik

1
@SiLo 일반적으로 두 개체가 같은 클래스인지 물어 보는 방법을 찾았습니까?
matt

1
@matt 우아하지 않고, 아니에요. 그러나 DefaultableC #의 default키워드 와 유사하게 작동 하는 프로토콜 과 StringInt. 일반적인 제약 조건을 추가하여 T:Defaultable인수가 전달되었는지 확인할 수 있습니다 is T.default().
Erik

1
@SiLo Clever; 그 코드를보고 싶습니다! 나는 이것이 "is"의 사용에 대한 이상한 제한을 우회한다고 생각한다. 나는 이러한 한계와 클래스 내성의 일반적인 부족에 대한 버그를 제출했습니다. NSStringFromClass를 사용하여 문자열을 비교했지만 물론 NSObject 하위 항목에서만 작동합니다.
matt

1
@ 매트는 불행하게도 당신이 아직도해야하기 때문에 실제보다 더 똑똑한 소리 value is String.default(), 등등 ... 그냥 일을 끝낼 것이다 value is String대신.
Erik

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

빙고, "makeFoo"는 Foo 인스턴스를 포함합니다.

단점은 클래스가 FactoryObject에서 파생되어야하고 Obj-C + initialize 메서드가 있어야 클래스가 전역 함수 "mapClass"에 의해 클래스 맵에 자동으로 삽입된다는 것입니다.


1

다음은 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()

이 결과를 인쇄합니다.

base
file
display
base
folder
display

2
이 기술은 변수가 수퍼 클래스의 유형 인 경우 올바르게 작동하지 않습니다. 예를 들어, 주어진 var x: NamedItem.Type내가 그것을 할당하면, x = Folder.Type다음, x()새로운를 반환 NamedItem하는 없습니다 Folder. 이것은 많은 응용 프로그램에서이 기술을 쓸모 없게 만듭니다. 나는 이것을 버그 라고 생각 한다 .
phatmann 2014

1
실제로이 기술을 사용하여 원하는 작업을 수행 할 수 있습니다. stackoverflow.com/questions/26290469/…
possen dec
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.