web-dev-qa-db-ja.com

Swift Objective-Cカテゴリのクラスを拡張する

私はObjective-Cカテゴリを使用してSwiftクラスを拡張する必要がある状況です。次のように何かを実行しました。

「SomeClass.Swift」では:

_class SomeClass: NSObject {
}
_

「SomeClass + Extension.h」で:

_#import "Project-Swift.h"
@interface SomeClass (Extension) 
-(void)someMethod();
@end
_

これはうまくいきました。また、Objective CコードでSomeClass拡張機能を使用しようとしても問題ありません。

問題は、別のSwiftクラスでsomeMethod()を使用する場合、_SomeClass+Extension.h_ファイルを_ObjC-BridgingHeader.h_に配置する必要があることです。ファイル。

ただし、_SomeClass+Extension.h_は_Project-Swift.h_もインポートするため、これを行うと循環依存が発生します。

これを回避する良い方法はありますか?

カテゴリはそれ自体の実装のために前方宣言を使用できないため、カテゴリヘッダーでクラスを単に前方宣言するだけでは機能しないことに注意してください。

_@class SomeClass_をインポートせずに_Project-Swift.h_を使用すると、コンパイルエラーが発生します。

24
stephen

悪い人

私もこの問題とたくさん戦っています。残念ながら documentation は、このパターンが許可されていないことをかなり明確に述べています:

循環参照を回避するには、SwiftコードをObjective-Cヘッダー(.h)ファイルにインポートしないでください。代わりに、Swift classまたは、Objective-Cインターフェイスで参照するためのプロトコル。

Swiftクラスおよびプロトコルの前方宣言は、メソッドおよびプロパティ宣言の型としてのみ使用できます。

また、リンクされたページ全体で、生成されたヘッダーを特に.mファイルにインポートすることについて言及し続けていることに気づくでしょう:

Swiftコードを同じターゲットからObjective-Cにインポートするには

Swiftコードをそのターゲットからそのターゲット内のObjective-C .mファイルにインポートします

いいもの

Swift拡張機能を作成して、カテゴリで必要な各メソッドを再定義します。これは脆弱で醜いですが、間違いなく最もクリーンなソリューションです。

/**
 Add category methods from objc here (since circular references prohibit the ObjC extension file)
 */
extension SomeClass {
    @nonobjc func someMethod() {
        self.performSelector(Selector("someMethod"))
    }
}
  • @noobjcを前に付けると、ObjC実装をオーバーライドせずに同じメソッドシグネチャを使用できます
  • import "SomeClass+Extension.h"ブリッジヘッダーから削除できます

3つ以上の入力パラメーターのサポートが必要な場合、またはより厳密な型の結合が必要な場合は、ランタイムを使用して基本となる関数を呼び出すことをお勧めします。すばらしい説明は ここ です。

17
Casey

相互運用性ガイド から、.Swift [SomeClass]クラスのサブクラス化/分類/拡張されたObjcオブジェクトに直接アクセスすることはできません。

しかし、ターンアラウンドとして、これを行うことができます:

変数の場合、これを行うことができます:

extension Class {
    private struct AssociatedKeys {
        static var DescriptiveName = "sh_DescriptiveName"
    }

    var descriptiveName: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
        }

        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.DescriptiveName,
                    newValue as NSString?,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
    }
}

メソッドには、推奨されないmethod_swizzlingを使用できます。

3
itechnician

簡単な解決策の1つとして、拡張機能をSwiftコードに移動できます。そうすれば、依存関係の問題は発生しなくなります。

2
Sulthan