web-dev-qa-db-ja.com

Objective-CにAPI可用性チェックがないのはなぜですか?

Swift 2にはAPI 可用性チェック があります。

最小のターゲットOSに対して新しすぎるAPIを使用すると、コンパイラーはエラーを表示します

Objective-Cコンパイラが同等の処理を実行できないのはなぜですか?

私はObjective C APIの可用性チェックをググりましたが、Swift 2の結果しか出ていないので、Objective Cのコンパイラーはそれができないと思います。

16
okysabeni

警告(Swiftがエラーにする)は、Clangコンパイラーで何年も実装されていなかっただけですが、Objective-C固有の制限ではありません(ただし、動的な性質のため、すべてのケースをキャッチすることはできません)。 、またSwift用語。

Appleマクロ(たとえば、_NS_CLASS_AVAILABLE_)とソース属性(__attribute__((visibility(...)))__attribute__((availability(...))))を使用して、ヘッダーに可用性情報の注釈を付けるマクロはFoundationの_NSObjCRuntime.h_および_Availability.h_/_AvailabilityMacros.h_システムヘッダーで定義されており、コンパイラは(そしてそうします)それらを読みます。

2015年の初めに、Clangのmasterブランチに_-Wpartial-availability_警告 が追加されました になりましたが、このコミット/警告は(含む)までAppleのバージョンのClangに反映されませんでした)Xcode 7.2。 Xcode 7.2でプロジェクトに警告フラグを追加すると、_unknown warning option_ログが表示されますが、このフラグはXcode 7.3で使用できます。現在のところ、事前定義された設定はありませんが、Build Settingsの下の_Other Warning Flags_にフラグを追加できます。

LLVMライブラリを使用して部分的に利用可能なAPIを検出する他のツールがあります(例: Deploymate )。卒業証書のために、Xcodeに直接統合するツールを開発しました。このツールは、Clangコンパイラの修正に基づいています。コードはまだ online ですが、一般的なClangの開発に追いついていないため、学習目的以外ではあまり役に立ちません。ただし、「公式」コード(上記にリンクされています)はよりクリーンで優れています。

編集:Xcode 9以降、可用性チェックはObjective-C(およびC)でも機能します。一時的またはローカルでの展開ターゲットの引き上げをサポートしていないため、多くの誤検知を引き起こす上記の警告フラグを使用する代わりに、_-Wunguarded-availability_、およびif (@available(iOS 11, *)) {...}を使用して、デプロイメントを確認して引き上げます次のコードブロックのターゲット。デフォルトではオフですが、_-Wunguarded-availability-new_はデフォルトでオンになり、iOS/tvOS 11、watchOS 4、およびHigh Sierra以外のすべてのチェックを開始します。詳細については Xcode 9ベータリリースノート を参照してください。現在、開発者アカウントでサインインする必要があります。

20
hagi

Xcode 9.0は、ランタイム可用性チェック構文をSwiftからObjective-Cにもたらします。

if (@available(macOS 10.9, *))
{
// call 10.9+ API
}
else
{
// fallback code
}

これには、デプロイメントターゲットよりも新しいAPIを呼び出す場合の警告が含まれています(これらの呼び出しがチェックにラップされていない場合)。

最後に ;)

46
user1259710

Objective Cプリプロセッサーを介して同じ結果が得られるため、Objective Cには言語の一部として可用性チェックがありません。これが、C派生言語でこれを行う「伝統的な」方法です。

デバッグモードでコンパイルされているかどうか知りたいですか?

#ifdef DEBUG
  // code which will be inserted only if compiled in debug mode
#endif 

コンパイル時に最小バージョンを確認したいですか? iOSのAvailability.hヘッダー、およびMac OS Xの同様のヘッダーを使用します。

このファイルは/ usr/includeディレクトリにあります。

プリプロセッサで__IPHONE_OS_VERSION_MAX_ALLOWEDをテストするだけです。例:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
            if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
                [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil]];
            }else{
                [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
            }
#else
            [[UIApplication sharedApplication] registerUserNotificationSettings: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
#endif

Swiftにはプリプロセッサがないため、言語自体の中でこれらの種類のチェックを行う方法を発明する必要がありました。

実行時にメソッドの可用性を確認する場合、適切な方法はメソッドrespondsToSelector:またはinstancesRespondToSelector:(後者はクラスレベル)を使用することです。 。

通常は、コンパイル時の条件付きコンパイルとランタイムチェックの両方のアプローチを組み合わせる必要があります。

客観的なCメソッドの存在確認(例:クラスレベル:

if ([UIImagePickerController instancesRespondToSelector:
              @selector (availableCaptureModesForCameraDevice:)]) {
    // Method is available for use.
    // Your code can check if video capture is available and,
    // if it is, offer that option.
} else {
    // Method is not available.
    // Alternate code to use only still image capture.
}

実行時にC関数が存在するかどうかをテストする場合は、さらに簡単です。存在する場合、関数自体はnullではありません。

両方の言語で同じ方法を使用することはできません。