ObjC: + da una falla incorrecta

De acuerdo, parece que aseverar +isSubclassOfClass: debería hacer el trabajo. Pero … no es así.

 @implementation OperationManagerClass - (void)registerClass:(Class)aClass forType:(NSString *)type { NSAssert([aClass isSubclassOfClass:[BaseClass class]); self.registenetworkingClasses[type] = aClass; } @end 

El aserto es siempre NO , incluso cuando se pasa la BaseClass .

¿Qué hay de viajar más arriba en la jerarquía de classs? NSOperation y NSObject responden 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 

BaseClass en count que los consumidores de la class de operación base son subclasss en el proyecto de aplicación de iOS, y OperationManagerClass y BaseClass están en una biblioteca estática incluida. ¿Por qué creo que esto podría tener algo que ver con isSubclassOfClass: estar equivocado? Debido a lo siguiente …

Todavía en libShanetworkingStuff.a

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

En objective de aplicación

 @interface OutsideClass : NSOperation @end @interface OutsideClassSubA : OutsideClass @end 

… produce los siguientes resultados cuando OutsideClassSubA se pasa en:

 (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 

¿Que está pasando aqui? ¿Por qué +isSubclassOfClass: dar la respuesta incorrecta? ¿Cómo puedo hacer cumplir que el parámetro aClass debe ser una subclass de mi BaseClass ?


Editar:
Me di count de que el ejemplo que publiqué funciona bien después de tirar las piezas en un espacio de trabajo Xcode separado. Publicé el código fuente del juguete desde arriba con un giro que dejé fuera de mi descripción original.

De hecho, tengo dos bibliotecas estáticas ( libShanetworkingStuff.a y libHelperShanetworkingStuff.a ). Los enlaces de destino de la aplicación con libShanetworkingStuff.a , y el objective de la testing de la unidad dependen del destino de la aplicación, así como de los enlaces libHelperShanetworkingStuff.a . Cuando BaseClass.m es miembro de los dos objectives de la biblioteca estática, entonces +isSubclassOfClass: fallará en +isSubclassOfClass: testing de unidades. Específicamente, falla cuando paso MockBaseClass , que es una subclass de BaseClass que es parte del objective de testing de la unidad.

Todo esto se ilustra en el proyecto vinculado anteriormente.

Como explico en la edición de mi pregunta, BaseClass.m en ambas librerías estáticas libShanetworkingStuff.a y libHelperShanetworkingStuff.a . Los enlaces de destino de la aplicación principal contra libShanetworkingStuff.a y los enlaces de destino de testing de unidad con libHelperShanetworkingStuff.a . Esto significa que cuando el package .xctest se inyecta en mi aplicación en time de ejecución, el símbolo de la BaseClass se define dos veces

( ¿Tal vez? ¿Es eso posible? ¿Qué sucede realmente en el time de ejecución? ).

Parece que en mi objective de testing de unidad MockSubclassOfBaseClass henetworkinga del símbolo de la BaseClass en libHelperShanetworkingStuff.a , mientras que en mi objective de aplicación SubclassOfBaseClass henetworkinga del símbolo de la BaseClass en libShanetworkingStuff.a . Si ese es el caso, entonces tiene sentido por qué +isSublcassOfClass: responde NO cuando se pasa MockSubclassOfBaseClass !

Cualquier respuesta que aclare, confirme u ofrezca una mejor idea de que tengo la idea correcta es muy apreciada.

Asegúrese de que la biblioteca estática esté haciendo que los símbolos estén vinculados correctamente. Mi suposition inmediata sería que las classs proporcionadas por lib estáticas pasadas como aClass son en realidad Nil en time de ejecución, y por lo tanto devolviendo 0 a cualquier post enviado.

Una forma de garantizar esto es hacer una function de constructor que los use:

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

Las classs débilmente vinculadas pueden ser un poco tramposas.

Si está utilizando los pods de cocoa, asegúrese de no vincular todos los pods al objective de testing.

Eso arregló el problema para mí.