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

.

enter image description here

Can someone explain why?

+3


source to share


2 answers


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

+1


source


I am assuming that it [UIView init]

is calling [self initWithFrame:CGRectZero]

, so it is calling your own method initWithFrame

since you overloaded it.



To solve your problems, you should just do the same :). init

should cause initWithFrame

, not vice versa.

+2


source







All Articles