Objective-C子类可以不调用init

时间:2013-08-17 06:51:29

标签: objective-c inheritance

我使用的是第三方库,它不会公开其init方法,并且会从类级别的消息中做一些专门的I-don -t-know-what。这是否禁止我进行子类化?

我做了一个测试用例(启用了ARC)

A.H

@interface A : NSObject 
@property (nonatomic, strong) NSString * bar;
-(id) initWithAbar:(NSString *) bar;
+(id) aWithBar:(NSString *) bar;
@end

A.M

#import "A.h"
@implementation A
-(id) initWithAbar:(NSString *) bar
{
    self = [super init];
    if (self) {
        self.bar = bar;
    }
    return self;
}


+(id) aWithBar:(NSString *) bar
{
    return [[A alloc] initWithAbar:bar];
}

@end

B.h

#import <Foundation/Foundation.h>
#import "A.h"

@interface B : A
@property (nonatomic, strong) NSString *foo;
-(id) initWithFoo:(NSString *)foo bar:(NSString *)bar;
@end

B.m

#import "B.h"

@implementation B

-(id) initWithFoo:(NSString *)foo bar:(NSString *)bar
{
    self = (B*)[A aWithBar:bar]; // Still actually A, knew that by printing [self class];
    if (self) {
        self.foo = foo; // Error: unrecognized selector here
    }
    return self;
}

@end

假设我不能只调用A initWithAbar:,我在子类A中有任何选择吗?如果A的aWithBar正在调用A的init,那么init的特别之处是什么?

1 个答案:

答案 0 :(得分:0)

注意:

  • - [NSObject init]仍然可用。如果班级的创建者非常小心,他们会覆盖init,因此会使用默认参数调用initWithBar:

  • 如果您使用运行时内省或class-dump来查找类A上的方法列表,那么您可以确实声明(可能在类别中)和致电- [A initWithBar:]

  • 但是如果你不想做任何这些(特别是#2,因为它是一个黑客),那么为什么不创建一个类似的便利方法?这样的事情:


@implementation B

+ (B *)beeWithBar:(NSString *)bar
{
    B *instance = [self aWithBar:bar];
    instance.someOtherProperty = 42;
    return instance;
}

@end

请注意,这仅在开发人员注意并使用aWithBar:实施[self initWithBar:]时才有效。如果类名是硬编码的(如您的示例所示),则无法通过调用便捷方法获取B的实例。