4
  • NSOperationクライアントが独自のロジックを追加するためにサブクラス化する必要がある基本クラスを定義する iOS 静的ライブラリがあります。@interface BaseClass : NSOperation

  • クライアントはサブクラスをマネージャーに登録します。-[OperationManagerClass registerClass:forType:]

  • マネージャーでは、サブクラスを登録する必要があることを強制したいBaseClassだけではありませんNSOperation

+isSubclassOfClass:さて、アサーションは仕事を終わらせる必要があるようです。しかし...そうではありません。

@implementation OperationManagerClass

- (void)registerClass:(Class)aClass forType:(NSString *)type
{
    NSAssert([aClass isSubclassOfClass:[BaseClass class]);

    self.registeredClasses[type] = aClass;
}

@end

アサートはNO、渡された場合でも常にBaseClassです。

クラス階層を上に移動するのはどうですか? NSOperationNSObject両方が応答しYESます!

(lldb) p (BOOL)[aClass isSubclassOfClass:[BaseClass class]]
(BOOL) $0 = NO
(lldb) po aClass
BaseClass
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSOperation class]]
(BOOL) $2 = YES
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSObject class]]
(BOOL) $3 = YES

基本操作クラスのコンシューマは、iOS アプリケーション プロジェクトでサブクラス化されてOperationManagerClassおりBaseClass、含まれている静的ライブラリに含まれています。isSubclassOfClass:これが間違っていることに関係があると思うのはなぜですか?以下の理由で...

まだ libSharedStuff.a にあります

@implementation OperationManagerClass

- (void)registerClass:(Class)aClass forType:(NSString *)type
{
    // Obviously OperationManagerClass.m cannot #import "OutsideClass.h"
    NSAssert([aClass isSubclassOfClass:NSClassFromString(@"OutsideClass");

    self.registeredClasses[type] = aClass;
}

@end

適用対象内

@interface OutsideClass : NSOperation
@end

@interface OutsideClassSubA : OutsideClass
@end

...OutsideClassSubAが渡されると、次の結果が得られます。

(lldb) p (BOOL)[aClass isSubclassOfClass:[OutsideClass class]]
(BOOL) $0 = YES
(lldb) po aClass
OutsideClassSubA
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSOperation class]]
(BOOL) $2 = YES
(lldb) p (BOOL)[aClass isSubclassOfClass:[NSObject class]]
(BOOL) $3 = YES

何が起きてる?なぜ+isSubclassOfClass:間違った答えを与えるのですか?aClassパラメータが my のサブクラスでなければならないことを強制するにはどうすればよいBaseClassですか?


編集:
投稿した例は、ピースを別の Xcode ワークスペースにプルした後、正常に動作することに気付きました。上記のおもちゃのソース コードを投稿しましたが、元の説明にはひねりが加えられていません。

私は実際に2 つの静的ライブラリ (libSharedStuff.alibHelperSharedStuff.a) を持っています。アプリケーション ターゲットは とリンクしlibSharedStuff.a、単体テスト ターゲットはアプリケーション ターゲットとリンクに依存しますlibHelperSharedStuff.aが両方の静的ライブラリ ターゲットBaseClass.mのメンバーである場合、単体テスト アサーションで失敗します。具体的には、単体テスト ターゲットの一部であるのサブクラスであるを渡すと失敗します。+isSubclassOfClass:MockBaseClassBaseClass

これらはすべて、上記のリンクされたプロジェクトに示されています。

4

3 に答える 3

7

質問の編集で説明したように、BaseClass.m静的ライブラリlibSharedStuff.alibHelperSharedStuff.a. メイン アプリケーション ターゲットは にリンクしlibSharedStuff.a、単体テスト ターゲットは にリンクしlibHelperSharedStuff.aます。これは、.xctestバンドルが実行時にアプリケーションに挿入されると、BaseClassシンボルが 2 回定義される ことを意味します。

(多分?それは可能ですか?実行時に実際に何が起こるのでしょうか? )。

単体テストでは、ターゲットはシンボル inMockSubclassOfBaseClassを継承しているようですが、アプリケーションでは、ターゲットはシンボル inを継承しています。その場合、が渡されたときにが応答する理由は理にかなっています。BaseClasslibHelperSharedStuff.aSubclassOfBaseClassBaseClasslibSharedStuff.a+isSublcassOfClass:NOMockSubclassOfBaseClass

ここで私が正しい考えを持っていることを明確にし、確認し、またはより良い洞察を与える答えは大歓迎です。

于 2013-11-10T16:08:16.540 に答える
1

静的ライブラリが実際にシンボルを正しくリンクしていることを確認してください。私の当面の推測では、aClass として渡された静的な lib 提供のクラスは、実行時に実際には Nil であり、したがって、送信されたすべてのメッセージに 0 を返します。

これを確実にする 1 つの方法は、それらを使用するコンストラクター関数を作成することです。

__attribute__((constructor)) static void EnsureClassesAreLoaded(void) {
    [BaseClass self];
}

弱いリンクのクラスは少し扱いに​​くい場合があります。

于 2013-11-09T22:14:27.213 に答える
1

ココア ポッドを使用している場合は、すべてのポッドをテスト ターゲットにリンクしていないことを確認してください。

これで問題は解決しました。

于 2015-01-07T10:25:47.987 に答える