如何将objective-c方法设为私有

时间:2012-12-22 18:17:50

标签: objective-c

  

可能重复:
  Why doesn’t Objective-C support private methods?
  Private Method Declaration Objective-C

我想要做的是在Objective C中实现特定方法的私有(使用Java术语)。也就是说,类可以根据需要调用该方法,而不必担心该方法将被子类覆盖。也许这个术语“不会被覆盖。”

作为一个例子,一个对象有多个init方法,并且有一个私有初始化方法来进行常见的初始化:

- (void) initWithFile:(NSString *)file
{
    if ((self = [super init]) != nil) {
        self.file = file;
        self.url = nil;
        [self initialize]
    }
    return self;
}

- (void) initWithURL:(NSURL *)url
{
    if ((self = [super init]) != nil) {
        self.url = url;
        self.file = nil;
        [self initialize]
    }
    return self;
}

- (void) initialize
{
    ...
}

这是有效的,如果在.h文件中没有声明初始化,则它被“保护”不被其他类调用。

我遇到了子类的问题(假设以下类是前一个例子的子类):

- (void) initWithFile:(NSString *)file
{
    if ((self = [super initWithFile:file]) != nil) {
        [self initialize];   // my local initializations
    }
    return self;
}

- (void) initialize
{
    ... // my private stuff
}

问题在于,在这个例子中,现在从不调用基类的initialize方法,并且子类的initialize方法被调用两次,因为子类的initialize方法覆盖了基类方法。

我知道我可以在子类中调用[super initialize],并省略子类init方法中的调用,但这需要子类知道基类的内部。由于子类不需要访问基类的源,并且只需要.h接口文件,因此它有充分的理由认为它可以实现初始化方法而不会导致更改行为的不必要的副作用基类。

我问这个是因为我有一个问题直接涉及未在初始化函数中设置的属性,只是发现它被子类篡改了,我花了一些时间来调试它。我想首先防止这种情况发生。

6 个答案:

答案 0 :(得分:1)

objC

中的方法没有私有或最终关键字

只是不要将它们包含在标题中......
或许以某种方式命名他们__XY左右......


btw:在java 私有中不反对覆盖,那只是另一个'副作用'。关键字 final 反对覆盖

答案 1 :(得分:1)

Objective-C中没有这样的东西。 你可以做的只是没有定义方法。

Apple经常这样做。

@interface SomeClass ()
- (void)_someNonPublicMethod;
@end

这是一个类别,它简单地说明了应该在课堂上定义的内容。 您可以在 .m 文件中执行此操作。

与已经提到的其他答案一样,您可以找出类使用类转储实现的方法,然后您可以覆盖它们,即使它们是私有的。

答案 2 :(得分:1)

一个相当可靠的解决方案是使用静态c方法进行初始化。所有有效的c都是有效的目标-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()

但是,您再次具体询问如何禁止自己覆盖常见的初始化方法,从而{{1}}解决方案。

答案 3 :(得分:0)

看看这个页面 它是关于最佳客观c代码实践 包括私人方法:)

http://ironwolf.dangerousgames.com/blog/archives/913

答案 4 :(得分:0)

这必须在.m文件中:

@interface MyClass()

- (void) privateMethod1;

@end

@implementation MyClass

@end

答案 5 :(得分:0)

@implementation中定义的或在无名称类别中声明的方法不可见,但可以执行它们。但是,真正的问题是您需要每个实例的初始化方法,但是:

  • 您希望此方法是私有的,但让此类的用户知道它存在,并且他们应该覆盖它。怎么样?未来你不会喜欢这个。
  • 您想要覆盖此方法并从另一个overriden方法调用它。这导致子方法的双重执行。

您尝试创建的约定没有意义。您应该为每个初始化方法指定一个不同的名称,并从init调用每个名称。