合适的Objective-C助手;私有方法

本文关键字:有方法 助手 Objective-C | 更新日期: 2023-09-27 18:04:18

虽然我讨厌在这个问题上喋喋不休(我已经阅读了关于这个问题的各种文章),但我只是想在我创建我自己的"惯例"之前得到更多关于这个问题的意见,从现在开始在Objective-C中编码时使用。

我想弄清楚的约定是最终如何(使用生产级代码的最佳编码实践)在类中使用私有方法。从c#的背景来看,当我编写类时,通常会有一个代码块在多个公共方法中重复(例如错误检查或WCF服务连接设置)。我通常创建这段代码的一个块,并将其放在一个私有方法中,只有这些公共方法才能访问。这样,如果我需要进行更改,我只需要在一个位置进行更改,而不是在一个类中的10个不同位置,但这样就永远不会让用户能够调用这个私有方法。例如:

public Class A
{
    public void method1()
    {
        doErrorChecking()
        // Do more stuff
    }
    public void method2()
    {
        doErrorChecking()
        // Do more stuff
    }     
    private doErrorChecking() { //Error Checking Code}
}

我明白在Objective-C中没有真正的方法来真正使最后一个方法私有,但只是真的想确保当我在Objective-C中为iOS开发创建所有未来的类时,我遵循了最佳实践,因此未来的代码重构在这个问题上将不需要(希望)。我注意到有人在谈论类别,其他人只是不把方法放在@interface文件中,还有人使用扩展方法。目前,我只是将方法实现放在@implementation文件中,而不是接口文件中。我还使"想要的"私有方法有一个真正独特的名称,以便子类化或重写方法不是问题。这是我应该走的路吗?或者对于这些特殊情况有没有更好的方法?

合适的Objective-C助手;私有方法

是的,想要将功能提取到另一个方法中是完全合理的。在我看来,做到这一点的最佳方法是使用类延续,您可以将您的私有方法声明放入其中。它可以在.m文件的@implementation块之上,所以它不在公共头文件中。

@interface MyClass ()
- (void)_privateMethod:(id)arg;
@end

类延续和正常类别(如@interface MyClass (PrivateMethods))之间的区别是编译器将要求您在主要的@implementation块中实现方法,而不是有一个单独的@implementation MyClass (PrivateMethods)块。在实现您所描述的帮助器方法时,这无疑是可取的。

在命名方面,_作为私有方法名(和ivar名)的开头是比较常见的,尽管不是每个人都这样做——显然苹果为自己保留了这个前缀,所以你应该选择一个不同的前缀。

我肯定会使用类扩展。在实现文件中,在@implementation:

上面包含如下内容
@interface A ()
- (void) doErrorChecking;
@end

然后根据需要在代码中使用该方法。尽管由于objective-c的动态特性,没有任何方法是真正私有的,这将使接口文件中的方法变得模糊,但从技术上讲,它仍然包含在你自己的"私有"接口中。一般来说,在.h文件中保留可供公共使用的方法和属性,而将私有使用的方法和属性限制在实现文件中的类扩展中。

如果您只是需要一组绝对不能被子类覆盖的可重用代码,那么您可以创建一个普通的C函数而不是方法。如果函数是在类@implementation块的作用域中声明的,它仍然可以访问对象的所有私有变量。但是,您需要传入一个指向self的指针,因为函数没有绑定到特定对象

所以它看起来像这样:

static BOOL isInValidState(MyClass *);
@implementation MyClass
static BOOL isInValidState(MyClass *self) {
    if (self->somePrivateIvar == nil) {
        return NO;
    }
    if ([self->someString isEqualToString:@"pigsAreFlying"]) {
        return NO;
    }
    return YES;
}
- (void)method1 {
    if (isInValidState(self) == NO) {
        return;
    }
    // Do whatever method 1 does
}
- (void)method2 {
    if (isInValidState(self) == NO) {
        return;
    }
    // Do whatever method 2 does
}
@end

因为函数不是类的方法列表的一部分,所以这个错误检查方法永远不能被重写。由于我们将其声明为static,因此它只能在该文件的作用域中访问,这意味着它实际上是私有的;它不能被任何其他类的对象调用