Бесконечный цикл при подклассификации MKAnnotationView и вызов init из initWithFrame: перегрузки
Имея этот случай XCTestCase:
- (void)testAllInitializersConfigureTheView {
BIStationAnnotationView *withFrame = [[BIStationAnnotationView alloc] initWithFrame:CGRectNull];
XCTAssertTrue(CGRectEqualToRect(withFrame.frame, CGRectMake(0.f, 0.f, 30.f, 40.f)), @"Frame should be fixed");
}
Тестирование подкласса MKAnnotationView:
- (id)init {
if (self = [super init]) {
self.frame = _myFrame;
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
return self = [self init];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
return self = [self init];
}
Я получаю бесконечный цикл, потому что initWithFrame
вызывает init
и init
вызывает initWithFrame
.
Может кто-нибудь объяснить, почему?
В Objective-C существует понятие назначенного инициализатора, который является наиболее важным и обычно наиболее конкретным инициализатором. Кроме того, могут быть инициализаторы удобства с более короткой сигнатурой, которые внутренне вызывают назначенный инициализатор. Cocoa следует за этим шаблоном, что означает, что инициализатор удобства [UIView init]
вызывает назначенный инициализатор [UIView initWithFrame:]
.
В вашем конкретном случае вы вызываете инициализатор удобства [self init]
из назначенного инициализатора [self initWithFrame:]
. Это неверно, потому что [self init]
вызовет [super init]
(который есть [UIView init]
) и что он следует за назначенной концепцией инициализатора и вызывает [self initWithFrame]
.
Чтобы решить эту проблему, вы должны вызвать [super initWithFrame:]
из [self initWithFrame:]
.
Вы можете узнать больше об этой теме в официальной документации Apple: https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/Initialization/Initialization.html#//apple_ref/doc/uid/TP40010810-CH6-SW3
Я предполагаю, что [UIView init]
вызывает [self initWithFrame:CGRectZero]
, поэтому он вызывает ваш собственный метод initWithFrame
, так как вы перегрузили его.
Чтобы решить свои проблемы, вы должны просто сделать то же самое:).init
должен вызывать initWithFrame
, а не наоборот.