继承 MKAnnotationView 并从 initWithFrame 调用 init 时无限循环:重载

Infinite loop when subclassing MKAnnotationView and calling init from initWithFrame: overloads

有这个 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

有人可以解释为什么吗?

我猜 [UIView init] 正在调用 [self initWithFrame:CGRectZero],所以它正在调用您自己的 initWithFrame 方法,因为您已经重载了它。

要解决你的问题,你应该简单地做同样的事情:)。 init 应该调用 initWithFrame 而不是相反。

在Objective-C中有指定初始化器的概念,它是最重要的,通常也是最具体的初始化器。此外,可能存在带有较短签名的便利初始化器,它们在内部调用指定的初始化器。 Cocoa 遵循此模式,这意味着便利初始化程序 [UIView init] 调用指定初始化程序 [UIView initWithFrame:].

在您的特定情况下,您从指定的初始值设定项 [self initWithFrame:] 调用便利初始值设定项 [self init]。这是错误的,因为 [self init] 将调用 [super init](即 [UIView init])并且那个遵循指定的初始化概念并调用 [self initWithFrame].

要解决此问题,您应该从 [self initWithFrame:].

中调用 [super initWithFrame:]

您可以在 Apple 的官方文档中阅读有关此主题的更多信息:https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/Initialization/Initialization.html#//apple_ref/doc/uid/TP40010810-CH6-SW3