2017-01-05 20 views
3

でNSClassFromStringを使用して、ネストしたクラスのインスタンス化。私は単純なクラスAのためにそれを行うことができましたが、NSClassFromStringパラメータに.B文字列をつけると、それは単にnilを返します。 は、私はこのように定義された入れ子になったクラスを持って迅速

NSClassFromString("\(appName).A") // works... 
NSClassFromString("\(appName).A.B") //doesn't work. 

は、私は、ネストされたクラス以降では使用できないと仮定しObjective-Cの NSClassFromStringちょうどその場合は...入れ子になったクラスの文字列からネストされたクラスを初期化する別の方法があると動作しませんか?あなたはフォーマットが完全に異なっている見ることができるように

"myApp.A" <---- STANDARD CLASS (A) 
"_TtCC15myApp13A6B" <----- NESTED CLASS (A.B) 

// EDIT

は標準クラスと入れ子になったクラスの実行時に異なるフォーマットを返しNSStringFromClass好奇心どのように逆関数です。 _TtCC15とはなんですか?なぜ "。"削除されましたか?私はそのフォーマットでクラスをNSClassFromStringに渡すと動作するはずです。

// inheriting NSObject is required for `@objc`, at which point `@objc` is optional 
class A: NSObject { 
    class B: NSObject { 
     override var description: String { return "foo" } 
    } 
} 

let str = NSStringFromClass(A.B.self) 
guard let anyClass = NSClassFromString(str) 
    else { fatalError("no class") } 
// cast to a type that defines `init()` so we can instantiate 
guard let nsClass = anyClass as? NSObject.Type 
    else { fatalError("class isn't NSObject") } 
// call `.init()`, not `nsClass()`; constructor syntax is for static types only 
let instance = nsClass.init() 
print(instance) // -> "foo" 

にObjCランタイムは、ネストされたクラス(または他の種類を理解していないので、変わり者クラス「名」の文字列がある:私は遊び場で、次の作品(Xcodeの8.2 /スウィフト3)ことがわかり

+1

クラスBを@objcとしてマークするようにしてください: '@objc class B {}'。 –

+0

既に試してみました...私は答えを更新します、それを指摘してくれてありがとう! – MatterGoal

+0

'class B 'の前に' public'キーワードを付けてみてください。この '@objc public class B'のように – NSDmitry

答えて

2

Swiftは定義できますが、ObjCではできません) - Swift自体の中で、そのような名前は、型、関数などが一意に定義される方法です。

ブリッジング機械はまだ動的にクラスが適切にマングルされたスウィフト名前を与えられた解決するために行うことができますが、スウィフト名前がマングル:(func foo()func foo(num: Int) -> Bool内部で別のマングルされた名前を持っている。例えば、名前の符号化は、関数のオーバーロードの作品がどのようにもあります)実装の詳細であり、変更される可能性があります。 (少なくともSwift 4がABIをロックするまで)NSStringFromClassの結果を同じプログラム内でNSClassFromStringに渡すことは安全ですが、テストで一度マングルされた名前を記録するのは安全ではなく、そのマングルされた名前を文字列として発送しますリテラルまたはリソースを使用して、後でNSClassFromStringで動作することを期待してください。あなたは、ネストされたクラス(またはその他のスウィフト定義のクラスは)にObjCランタイムで使用するために確実に知られている名前を持つようにしたい場合は(the docsで説明したように)

代わりに、それを@objc(name)を与える:

@objc class A: NSObject { 
    @objc(A_B) class B: NSObject { /*...*/ } 
} 
guard let anyClass = NSClassFromString("A_B") 
    else { fatalError("no class") } 

(このスニペットは単独では実行されません - クラスA.Bは、ObjCランタイムに登録するために少なくともプロセスのどこかで参照される必要があります)これは、アプリケーションのどこかにlet t = A.B.self起動コード)

+0

ObjCの名前を使用してトリックをしました!あなたの答えの残りについて、すばらしい説明! – MatterGoal

関連する問題