Ordem de método de carregamento alterada no Xcode 7
Eu descobri que o Xcode 7 (Versão 7.0 (7A220)) mudou a ordem em que+load
métodos para classes e categorias são chamados durante testes de unidade.
Se uma categoria pertencente ao alvo de teste implementar um+load
agora é chamado no final, quando instâncias da classe já podem ter sido criadas e usadas.
eu tenho umAppDelegate
, que implementa+load
método. oAppDelegate.m
arquivo também contémAppDelegate (MainModule)
categoria. Além disso, há um arquivo de teste de unidadeLoadMethodTestTests.m
, que contém outra categoria -AppDelegate (UnitTest)
.
Ambas as categorias também implementam+load
método. A primeira categoria pertence ao alvo principal, a segunda - ao alvo de teste.
Eu fiz um pequenoprojeto de teste para demonstrar o problema. Trata-se de um projeto Xcode padrão vazio, com apenas dois arquivos alterados.
AppDelegate.m:
#import "AppDelegate.h"
@implementation AppDelegate
+(void)load {
NSLog(@"Class load");
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"didFinishLaunchingWithOptions");
return YES;
}
@end
@interface AppDelegate (MainModule)
@end
@implementation AppDelegate (MainModule)
+(void)load {
NSLog(@"Main Module +load");
}
@end
E um arquivo de teste de unidade (LoadMethodTestTests.m):
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "AppDelegate.h"
@interface LoadMethodTestTests : XCTestCase
@end
@interface AppDelegate (UnitTest)
@end
@implementation AppDelegate (UnitTest)
+(void)load {
NSLog(@"Unit Test +load");
}
@end
@implementation LoadMethodTestTests
-(void)testEmptyTest {
XCTAssert(YES);
}
@end
TestandoEu realizei o teste de unidade deste projeto (o código e o link do github estão abaixo) no Xcode 6/7 e obtive o seguinte+load
ordem de chamadas:
Xcode 6 (iOS 8.4 simulator):
Unit Test +load
Class load
Main Module +load
didFinishLaunchingWithOptions
Xcode 7 (iOS 9 simulator):
Class load
Main Module +load
didFinishLaunchingWithOptions
Unit Test +load
Xcode 7 (iOS 8.4 simulator):
Class load
Main Module +load
didFinishLaunchingWithOptions
Unit Test +load
Pergunta, questãoXcode 7 executa a categoria de destino de teste+load
método (Unit Test +load
) no final, após oAppDelegate
já foi criado.É um comportamento correto ou é um bug que deve ser enviado à Apple?
Pode não estar especificado, portanto, o compilador / tempo de execução é livre para reorganizar as chamadas? Eu dei uma olhadaesta pergunta SO bem como no+ descrição da carga na documentação do NSObject mas eu não entendi direito como+load
O método deve funcionar quando a categoria pertence a outro destino.
Ou talvezAppDelegate
há algum tipo de caso especial por algum motivo?
applicationDidFinishLaunchingWithOptions
é realizado antes do swizzling ocorrer. Acredito que existem outras maneiras de fazer isso, mas me parece contra-intuitivo o modo como funciona no Xcode 7. Pensei que quando uma classe é carregada na memória,+load
desta classe e+load
métodos de todas as suas categorias devem ser chamados antes que possamos algo com essa classe (como criar uma instância e chamardidFinishLaunching...
)