弱いリンク-クラスが存在するかどうかを確認し、そのクラスを使用します


87

ユニバーサルiPhoneアプリを作成しようとしていますが、SDKの新しいバージョンでのみ定義されているクラスを使用しています。フレームワークは古いシステムに存在しますが、フレームワークで定義されたクラスには存在しません。

ある種の弱いリンクを使用したいのはわかっていますが、実行時の関数の存在チェックに関するドキュメントを見つけることができます-クラスが存在することを確認するにはどうすればよいですか?


クラスは何ですか?多分他の回避策があります。
Marcelo Cantos

回答:


164

TLDR

電流:

  • スウィフトif #available(iOS 9, *)
  • Obj-C、iOSif (@available(iOS 11.0, *))
  • Obj-C、OS Xif (NSClassFromString(@"UIAlertController"))

レガシー:

  • Swift(2.0より前のバージョン)if objc_getClass("UIAlertController")
  • Obj-C、iOS(4.2より前のバージョン)if (NSClassFromString(@"UIAlertController"))
  • Obj-C、iOS(11.0より前のバージョン)if ([UIAlertController class])

Swift 2+

これまで、特定のOSバージョンではなく機能(またはクラスの存在)をチェックすることが推奨されていましたが、可用性チェックが導入されたため、Swift 2.0ではうまく機能しません。

代わりにこの方法を使用します。

if #available(iOS 9, *) {
    // You can use UIStackView here with no errors
    let stackView = UIStackView(...)
} else {
    // Attempting to use UIStackView here will cause a compiler error
    let tableView = UITableView(...)
}

注:代わりにを使用しようとするobjc_getClass()と、次のエラーが発生します。

⛔️ 'UIAlertController'はiOS 8.0以降でのみ使用できます。


Swiftの以前のバージョン

if objc_getClass("UIAlertController") != nil {
    let alert = UIAlertController(...)
} else {
    let alert = UIAlertView(...)
}

objc_getClass() よりも信頼性がありますNSClassFromString()objc_lookUpClass()


Objective-C、iOS 4.2以降

if ([SomeClass class]) {
    // class exists
    SomeClass *instance = [[SomeClass alloc] init];
} else {
    // class doesn't exist
}

詳細については、code007の回答を参照してください


OS Xまたは以前のバージョンのiOS

Class klass = NSClassFromString(@"SomeClass");
if (klass) {
    // class exists
    id instance = [[klass alloc] init];
} else {
    // class doesn't exist
}

を使用しNSClassFromString()ます。が返されたnil場合、クラスは存在しません。それ以外の場合は、使用可能なクラスオブジェクトを返します。

これはAppleによるとこのドキュメントで推奨されている方法です:

[...]コードは、[a]クラスの存在をテストし、 NSClassFromString()[the]クラスが存在する場合は有効なクラスオブジェクトを返し、存在しない場合はnilを返します。クラスが存在する場合、コードはそれを使用できます[...]


ありがとう。他の人の答えを完成させるために、クラスを検出したら、Classによって返されたインスタンスを使用してクラスを作成しNSClassFromString(に割り当てますid)、そのインスタンスでセレクターを呼び出します。
psychotik 2010年

2
特に、これはOSXでの唯一の方法ですが、iOS(4.2以降)では「最善」の方法ではありませんが、機能します。具体的には、code007のiOS向けの回答を参照してください。
Ben Mosher 2013年

クラスが実際のクラスではなくC構造体である場合はどうなりますか?
Nathan H

Swift 4.1には新しいチェックが付属していcanImportます。プロポーザル
ディスパッチ

69

iOS 4.2以降のベースSDKを使用する新しいプロジェクトの場合、NSObjectクラスのメソッドを使用して、実行時に弱くリンクされたクラスの可用性を確認するという、この新しい推奨アプローチがあります。すなわち

if ([UIPrintInteractionController class]) {
    // Create an instance of the class and use it.
} else {
    // Alternate code path to follow when the
    // class is not available.
}

ソース:https : //developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-SW3

このメカニズムは、iOSのほとんどのフレームワークで使用可能なNS_CLASS_AVAILABLEマクロを使用します(NS_CLASS_AVAILABLEをまだサポートしていないフレームワークがある可能性があることに注意してください-これについては、iOSリリースノートを確認してください)。上記のAppleのドキュメントリンクで読むことができる追加の設定も必要になる場合がありますが、この方法の利点は静的な型チェックができることです。


3
ゲームに少し遅れましたが、UIAlertControlleriOS 7をサポートしながらコードをビルドしようとしたときにこの問題に遭遇しました。code007の答えは正しいですが、必要な追加の構成は、プロジェクトのUIKit を弱くリンクする(からRequiredに設定するOptional)ものです(少なくともこの状況では)。
エヴァンR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.