一个相当可靠的解决方案是使用静态 c 方法进行初始化。毕竟所有有效的c都是有效的objective-c。
例如,CustomSuperclass.h:
#import <Foundation/Foundation.h>
@interface CustomSuperclass : NSObject
@property (nonatomic) NSUInteger integer;
@end
CustomSuperclass.m:
#import "CustomSuperclass.h"
@implementation CustomSuperclass
@synthesize integer = _integer;
static void initializeInstance(CustomSuperclass *self) {
self.integer = 9;
}
-(id)init{
if ((self = [super init])){
initializeInstance(self);
}
return self;
}
@end
CustomSubclass.h:
#import "CustomSuperclass.h"
@interface CustomSubclass : CustomSuperclass
@end
CustomSubclass.m:
#import "CustomSubclass.h"
@implementation CustomSubclass
// Obviously we would normally use (CustomSubclass *self), but we're proving a point with identical method signatures.
void initializeInstance(CustomSuperclass *self) {
self.integer = 10;
}
-(id)init{
if ((self = [super init])){
// We won't call this classes `initializeInstance()` function.
// We want to see if this one overrides it's superclasses version.
}
return self;
}
@end
现在如果你运行这样的代码:
CustomSuperclass *instanceOfSuperclass = [[CustomSuperclass alloc] init];
NSLog(@"superclass integer:%i", instanceOfSuperclass.integer);
CustomSubclass *instanceOfSubclass = [[CustomSubclass alloc] init];
NSLog(@"subclass integer:%i", instanceOfSubclass.integer);
你会看到:
superclass integer:9
subclass integer:9
如果子类的initializeInstance() 版本是子类使用的版本(调用[super init] 时),那么子类整数将为10。这证明了超类的initializeInstance() 方法未被覆盖(在至少在超类的范围内)由子类的版本决定。
根据评论进行编辑:
我发布了这个答案及其解决方案,不是因为我认为这是解决问题的最佳方法,而是因为它符合问题的规范。问题本质上是,“我如何强制动态语言以静态方式运行,这样我就不必遵循正常的命名/初始化约定?”
处理这种情况的最佳方法是让您的类有一个指定的初始化程序,每个初始化程序都会调用该初始化程序。喜欢:
/* Designated initializer */
-(id)initWithFile:(NSString *)file andURL:(NSURL *)url{
if ((self = [super init])){
_url = url;
_file = file;
// Initialization of new instance code here.
}
return self;
}
-(id)initWithFile:(NSString *)file{
return [self initWithFile:file andURL:nil];
}
-(id)initWithURL:(NSURL *)url{
return [self initWithFile:nil andURL:url];
}
指定的初始化程序几乎适用于所有情况。它们对于 UIView 子类来说有点麻烦,因为 IB UIView 将调用 initWithCoder: ,而代码实例化 UIView 将/应该调用 initWithFrame:。在这种情况下,可能会在调用[super initWith...] 之后编写一个通用方法来完成以减少代码重复。
在覆盖通用初始化方法的名称时可能会遇到问题。对于大多数人来说,这就是通过默默无闻来获得一点安全性的地方,例如:
-(void)initialize_CustomUIView{
// Common init tasks
}
-(id)initWithFrame:(CGRect)frame{
if ((self = [super initWithFrame:frame])){
[self initialize_CustomUIView];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
[self initialize_CustomUIView];
}
return self;
}
-(id)init{
if ((self = [super init])){
[self initialize_CustomUIView];
}
return self;
}
但是,您再次询问如何禁止自己覆盖通用初始化方法,因此是 static void initializeInstance() 解决方案。