Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Objective-C中为类定义私有方法的最佳方法_Objective C_Cocoa_Code Completion - Fatal编程技术网

在Objective-C中为类定义私有方法的最佳方法

在Objective-C中为类定义私有方法的最佳方法,objective-c,cocoa,code-completion,Objective C,Cocoa,Code Completion,我刚开始编写Objective-C,有Java背景,想知道编写Objective-C程序的人是如何处理私有方法的 我知道可能有几个惯例和习惯,并将这个问题看作是人们在Objective-C中处理私有方法时使用的最佳技术的集合 请在发布时为您的方法提供一个参数。为什么它好?它有哪些缺点(你知道的)以及你如何处理它们 至于我目前的发现 可以使用MyClass.m文件中定义的[例如MyClass(Private)]对私有方法进行分组 这种方法有两个问题: Xcode(和编译器?)不检查是否在相应的@

我刚开始编写Objective-C,有Java背景,想知道编写Objective-C程序的人是如何处理私有方法的

我知道可能有几个惯例和习惯,并将这个问题看作是人们在Objective-C中处理私有方法时使用的最佳技术的集合

请在发布时为您的方法提供一个参数。为什么它好?它有哪些缺点(你知道的)以及你如何处理它们


至于我目前的发现

可以使用MyClass.m文件中定义的[例如MyClass(Private)]对私有方法进行分组

这种方法有两个问题:

  • Xcode(和编译器?)不检查是否在相应的@implementation块中定义了私有类别中的所有方法
  • 您必须将@interface声明您的私有类别放在MyClass.m文件的开头,否则Xcode会发出类似“self可能不响应消息”privateFoo的消息
  • 第一个问题可以通过[例如MyClass()]解决。

    第二个问题让我很困扰。我希望看到私有方法在文件末尾附近被实现(和定义);我不知道这是否可能。

    虽然我不是Objective-C专家,但我个人只是在类的实现中定义了该方法。当然,它必须在(上面)之前定义任何方法都可以调用它,但它肯定只需要最少的工作量。

    没有真正的“私有方法”“在Objective-C中,如果运行时能够确定使用哪个实现,那么它将完成这项工作。但这并不是说没有方法不是文档化接口的一部分。对于那些方法,我认为分类是好的。我不会像第2点那样将
    @interface
    放在.m文件的顶部,而是将其放在自己的.h文件中。我遵循的一个约定(在其他地方也看到过,我认为这是苹果的约定,因为Xcode现在自动支持它)是以类和类别命名这样的文件,并用+分隔它们,因此
    @interface GLObject(PrivateMethods)
    可以在
    GLObject+PrivateMethods.h
    中找到。提供头文件的原因是,您可以在单元测试类中导入它:-)

    顺便说一下,就在.m文件末尾附近实现/定义方法而言,您可以通过在.m文件底部实现类别来实现类别:

    @implementation GLObject(PrivateMethods)
    - (void)secretFeature;
    @end
    
    @interface MyClass()
    
    - (void)myPrivateMethod;
    
    @end
    
    @implementation MyClass
    
    - (void)myPublicMethod {
        // Implementation goes here
    }
    
    - (void)myPrivateMethod {
        // Implementation goes here
    }
    
    @end
    
    或者使用类扩展(您称之为“空类别”),只需最后定义这些方法。Objective-C方法可以在实现中以任何顺序定义和使用,因此没有什么可以阻止您将“private”方法放在文件末尾

    即使使用类扩展,我也会经常创建一个单独的头(
    GLObject+Extension.h
    ),以便在需要时使用这些方法,模仿“朋友”或“受保护”的可见性


    因为这个答案最初是编写的,所以clang编译器已经开始对Objective-C方法进行两次传递。这意味着您可以避免完全声明“私有”方法,无论它们位于调用站点的上方还是下方,编译器都会找到它们。

    无法回避问题2。这就是C编译器(以及Objective-C编译器)的工作方式。如果使用XCode编辑器,函数弹出窗口应该可以轻松导航文件中的
    @接口
    @实现
    块。

    您可以尝试在实现下方或上方定义一个静态函数,该函数将指针指向您的实例。它将能够访问您的任何实例变量

    //.h file
    @interface MyClass : Object
    {
        int test;
    }
    - (void) someMethod: anArg;
    
    @end
    
    
    //.m file    
    @implementation MyClass
    
    static void somePrivateMethod (MyClass *myClass, id anArg)
    {
        fprintf (stderr, "MyClass (%d) was passed %p", myClass->test, anArg);
    }
    
    
    - (void) someMethod: (id) anArg
    {
        somePrivateMethod (self, anArg);
    }
    
    @end
    

    正如其他人所说,Objective-C中没有私有方法。但是,从Objective-C2.0(意味着Mac OS X Leopard、iPhone OS 2.0和更高版本)开始,您可以创建一个名为Class Extension的空类别(即
    @interface MyClass()
    )。类扩展的独特之处在于,方法实现必须与公共方法位于相同的
    @implementation MyClass
    中。所以我的课程结构如下:

    在.h文件中:

    @interface MyClass {
        // My Instance Variables
    }
    
    - (void)myPublicMethod;
    
    @end
    
    在.m文件中:

    @implementation GLObject(PrivateMethods)
    - (void)secretFeature;
    @end
    
    @interface MyClass()
    
    - (void)myPrivateMethod;
    
    @end
    
    @implementation MyClass
    
    - (void)myPublicMethod {
        // Implementation goes here
    }
    
    - (void)myPrivateMethod {
        // Implementation goes here
    }
    
    @end
    

    我认为这种方法的最大优点是,它允许您按功能而不是按顺序(有时是任意的)对方法实现进行分组公共/私有的区别。

    如果您想避免顶部的
    @接口
    块,您可以将私有声明放在另一个文件
    MyClassPrivate.h
    中,这并不理想,但不会影响实现

    MyClass.h

    interface MyClass : NSObject {
     @private
      BOOL publicIvar_;
      BOOL privateIvar_;
    }
    
    @property (nonatomic, assign) BOOL publicIvar;
    //any other public methods. etc
    @end
    
    MyClassPrivate.h

    @interface MyClass ()
    
    @property (nonatomic, assign) BOOL privateIvar;
    //any other private methods etc.
    @end
    
    我的班级

    #import "MyClass.h"
    #import "MyClassPrivate.h"
    @implementation MyClass
    
    @synthesize privateIvar = privateIvar_;
    @synthesize publicIvar = publicIvar_;
    
    @end
    

    Objective C中的每个对象都符合NSObject协议,该协议保留了性能选择器:方法。我之前也在寻找一种方法来创建一些不需要公开的“助手或私有”方法。如果您想创建一个没有开销的私有方法,并且不必在头文件中定义它,那么请尝试一下

    使用与下面代码类似的签名定义您的方法

    -(void)myHelperMethod: (id) sender{
         // code here...
    }
    
    然后,当您需要引用该方法时,只需将其作为选择器调用

    [self performSelector:@selector(myHelperMethod:)];
    

    这行代码将调用您创建的方法,并且不会出现关于未在头文件中定义该方法的恼人警告。

    缺少私有方法有一个好处。您可以将要隐藏的逻辑移动到单独的类中,并将其用作委托。在这种情况下,您可以将委托对象标记为private,并且从外部看不到它。将逻辑移动到单独的类(可能几个)可以更好地设计项目。使您的类变得更简单,并且将您的方法分组到具有专有名称的类中。

    您可以使用块吗

    @implementation MyClass
    
    id (^createTheObject)() = ^(){ return [[NSObject alloc] init];};
    
    NSInteger (^addEm)(NSInteger, NSInteger) =
    ^(NSInteger a, NSInteger b)
    {
        return a + b;
    };
    
    //public methods, etc.
    
    - (NSObject) thePublicOne
    {
        return createTheObject();
    }
    
    @end
    
    我知道这是一个老问题,但这是我在寻找时发现的第一个问题
    @interface MONObject : NSObject
    
    // public declaration required for clients' visibility/use.
    @property (nonatomic, assign, readwrite) bool publicBool;
    
    // public declaration required for clients' visibility/use.
    - (void)publicMethod;
    
    @end
    
    @interface MONObject ()
    @property (nonatomic, assign, readwrite) bool privateBool;
    
    // you can use a convention where the class name prefix is reserved
    // for private methods this can reduce accidental overriding:
    - (void)MONObject_privateMethod;
    
    @end
    
    // The potentially good thing about functions is that they are truly
    // inaccessible; They may not be overridden, accidentally used,
    // looked up via the objc runtime, and will often be eliminated from
    // backtraces. Unlike methods, they can also be inlined. If unused
    // (e.g. diagnostic omitted in release) or every use is inlined,
    // they may be removed from the binary:
    static void PrivateMethod(MONObject * pObject) {
        pObject.privateBool = true;
    }
    
    @implementation MONObject
    {
        bool anIvar;
    }
    
    static void AnotherPrivateMethod(MONObject * pObject) {
        if (0 == pObject) {
            assert(0 && "invalid parameter");
            return;
        }
    
        // if declared in the @implementation scope, you *could* access the
        // private ivars directly (although you should rarely do this):
        pObject->anIvar = true;
    }
    
    - (void)publicMethod
    {
        // declared below -- but clang can see its declaration in this
        // translation:
        [self privateMethod];
    }
    
    // no declaration required.
    - (void)privateMethod
    {
    }
    
    - (void)MONObject_privateMethod
    {
    }
    
    @end
    
    @implementation MyClass 
    // .. public methods
    
    # pragma mark private 
    // ...
    
    @end