Infinite loop when subclassing MKAnnotationView and calling init from initWithFrame: overloads
Having this XCTestCase case:
- (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");
}
Testing MKAnnotationView subclass :
- (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];
}
I get an infinite loop because it initWithFrame
calls init
and init
calls initWithFrame
.
Can someone explain why?
source to share
In Objective-C, there is the concept of a designated initializer, which is the most important and usually the most specific initializer. In addition, there may be shorter signature convenience initializers that internally call the designated initializer. Cocoa follows this pattern, which means that the convenience initializer [UIView init]
invokes the designated initializer [UIView initWithFrame:]
.
In your specific case, you are calling the convenience initializer [self init]
from the designated initializer [self initWithFrame:]
. This is not true because it [self init]
will call [super init]
(which is [UIView init]
) and that it follows the assigned initializer concept and calls [self initWithFrame]
.
To fix this problem, you must call [super initWithFrame:]
from [self initWithFrame:]
.
You can read more about this topic in the official Apple documentation: https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/Initialization/Initialization.html#//apple_ref/doc/uid/TP40010810- CH6-SW3
source to share