NSProxy, претендующий на класс, не обрабатывает отклики в 64-битной среде

В OCMockito тестовые дубликаты реализованы с помощью NSProxy. Двойное положение для экземпляра реализует -respondsToSelector: следующее:

- (BOOL)respondsToSelector:(SEL)aSelector {
    return [_mockedClass instancesRespondToSelector:aSelector];
}

Но двойное положение для класса реализует -respondsToSelector: как это:

- (BOOL)respondsToSelector:(SEL)aSelector {
    return [_mockedClass respondsToSelector:aSelector];
}

Это все работает в 32-разрядной среде выполнения. Например, если _mockedClass является [NSString class], прокси правильно отвечает, что отвечает на селектор +pathWithComponents:

Но в 64-разрядной среде выполнения происходит сбой:

Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT

Application Specific Information:
objc[1868]: GC: forcing GC OFF because OBJC_DISABLE_GC is set

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libobjc.A.dylib                 0x00007fff95cbffc6 cache_getImp + 6
1   libobjc.A.dylib                 0x00007fff95ccd1dc lookUpImpOrForward + 50
2   libobjc.A.dylib                 0x00007fff95ccd198 lookUpImpOrNil + 20
3   libobjc.A.dylib                 0x00007fff95cc218a class_respondsToSelector + 37
4   com.apple.CoreFoundation        0x00007fff91c131ad ___forwarding___ + 429
5   com.apple.CoreFoundation        0x00007fff91c12f78 _CF_forwarding_prep_0 + 120
6   org.mockito.OCMockitoTests      0x000000010451a55b -[StubClassTest testStubbedMethod_ShouldReturnGivenObject] + 107 (StubClassTest.m:48)

Обратите внимание, что это звонит class_respondsToSelector(…), Я подозреваю, что меня укусила оптимизация, сделанная во время выполнения. Что я могу сделать, чтобы это исправить?

1 ответ

Решение

Это немного длинный ответ, так что терпите меня. Я запустил простой код, чтобы проверить поведение:

Class mock = mockClass([NSProcessInfo class]);
[mock processInfo];
[verify(mock) processInfo];

Действительно, происходит сбой с неправильным указателем исключения. Замена первой строки

id mock = mockClass([NSProcessInfo class]);

работает как положено. Я подумал, что, возможно, стоит взглянуть на код после ARC. Эти фрагменты немного длинны, поэтому вот суть: Class тест, id тест

Как вы можете видеть, когда вы объявляете переменную типа Class есть дополнительный release, Я предполагаю, что, так как классы зарегистрированы в течение всего времени выполнения (если они не были удалены с помощью API времени выполнения), все в порядке Class переменная как __unsafe_unretained,

Подводя итог, у вас есть два возможных решения:

@implementation StubClassTest
{
    __strong Class mockClass;
}

или же

@implementation StubClassTest
{
    id mockClass;
}

кажется, решить проблему для меня.

Обновить

В особом случае, если базовым типом объекта является класс (возможно, квалифицированный по протоколу), тип настраивается таким образом, чтобы вместо него иметь квалификацию __unsafe_unretained.

От http://clang.llvm.org/docs/AutomaticReferenceCounting.html

Другие вопросы по тегам