1

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

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

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

#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

溴化氢

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

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

BM

#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's initWithAbar:,那么我在继承 A 时有什么选择吗?如果 A 的 aWithBar 调用了 A 的 init,那么 init 有什么特别之处呢?

4

1 回答 1

0

笔记:

  • - [NSObject init]仍然可用。如果该类的创建者很小心,他们就会被覆盖init,因此它initWithBar:使用默认参数进行调用。

  • 如果您使用运行时自省或class-dump找出 class 上的方法列表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通过调用便捷方法来获取的实例。

于 2013-08-17T07:14:35.267 回答