web-dev-qa-db-ja.com

Swiftクラスのイントロスペクションとジェネリック

ジェネリックを使用してclassインスタンスベースの型を動的に作成しようとしていますが、クラスのイントロスペクションで問題が発生しています。

質問は次のとおりです。

  • Obj-Cのself.classと同等のSwiftはありますか?
  • AnyClassからのNSClassFromStringの結果を使用してクラスをインスタンス化する方法はありますか?
  • AnyClassを取得する方法や、汎用パラメーターTから厳密に情報を入力する方法はありますか? (C#のtypeof(T)構文に類似)
116
Erik

1つは、[NSString class]に相当するSwiftは.selfです( Metatype docs を参照してください。

実際、NSString.classは機能しません! NSString.selfを使用する必要があります。

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

同様に、Swiftクラスで試しました...

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は遊び場でエラーを出します。

106
Jiaaro

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変更された名前を指定することに注意してください。それ以外の場合は、各クラスを指定する変更された文字列がわからないため、これは重要です。

これで、NSClassFromStringを使用してZorkクラスまたはZilkクラスを作成できます。これは、NSObjectとして入力でき、後でクラッシュしないことがわかっているためです。

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

そしてそれは可逆的です。 println(NSStringFromClass(anObject.dynamicType))も機能します。

47
matt

ドキュメントの権利を読んでいる場合、インスタンスを処理している場合、与えられたオブジェクトと同じTypeの新しいインスタンスを返したい場合、Typeはinit()で構築できます:

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

Stringですばやくテストしました。

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

うまくいきました。

13
monkeydom

In Swift

object.dynamicType

非推奨です。

代わりに使用します:

type(of:object)
13
J.beenie

型の比較の迅速な実装

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

注:オブジェクトが拡張する場合としない場合があるプロトコルでも機能することに注意してください

7
eonist

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
1
possen

ようやく機能するようになりました。少し怠laですが、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から派生する必要があり、グローバル関数「mapClass」によってクラスマップにクラスが自動的に挿入されるように、Obj-C + initializeメソッドを持たなければならないことです。