【问题标题】:Objective C Private Public Methods In Same Category同一类别中的 Objective C 私有公共方法
【发布时间】:2012-12-07 08:45:23
【问题描述】:

我想做的是将类别的方法分为私有方法和公共方法。 私有方法需要在该类别的文件之外可见,而不是在类之外。

例如,假设我有以下文件:

ClassA.m
ClassA.h // <-- Includes definitions of public category methods
ClassAPrivates.h // <-- Includes definition of private category methods.
ClassA+Render.m

ClassAPrivates.h 看起来像这样:

@interface ClassA()
// private methods here, for use inside ClassA
@end
@interface ClassA(Render)
// the private methods of the Render category.
-(void)privateConfigureDeviceContext;
-(void)privateConfigureBufferSpace;
@end

“ClassA.h”看起来像这样:

@interface ClassA : NSObject
// public methods of ClassA
@end
@interface ClassA (Render)
// public methods of category Render
-(void)drawLine;
-(void)drawCircle;
@end

但是,XCode 抱怨 Render 的重复接口。有什么解决方法吗?

【问题讨论】:

    标签: objective-c cocoa


    【解决方案1】:

    无需为私有方法创建单独的类别。

    有3种情况:

    1. ClassA+Render.m 访问在 ClassA.m 中定义的私有方法
    2. ClassA.m 访问在 ClassA+Render.m 中定义的私有方法
    3. ClassA+Render.m 访问ClassA.m 中定义的属性

    注意:虽然原发帖人没有要求场景 3,但我认为它可能会派上用场

    示例

    ClassA.m 定义了 2 个私有方法

    • basePrivateMethod1 - 这将调用 renderPrivateMethod1
    • basePrivateMethod2

    ClassA+Render.m 定义了 2 个私有方法

    • renderPrivateMethod1
    • renderPrivateMethod2 - 这将调用 basePrivateMethod2

    场景 1

    • ClassA+Render.m 中只需创建一个扩展并转发声明您要使用的方法。

    ClassA+Render.m

    @interface ClassA ()
    
    - (void) basePrivateMethod1; //Just forward declare the method
    
    @end
    

    场景 2

    • ClassA+Render.h 中只声明ClassA+Render.m 中定义的方法。
    • ClassA.m 中只包含 (#import) ClassA+Render.h
    • 请注意,ClassA+Render.h 将/不应在ClassA 之外使用

    ClassA+Render.h

    @interface ClassA (Render)
    {
        - (void) basePrivateMethod2;
    }
    

    场景 3

    • 请注意 - 无法在类别中定义/创建属性
    • 因此创建一个名为ClassA+Properties 的新类别
    • ClassA+Properties.h重新声明所有属性
    • ClassA+Properties.m 中对所有属性使用@dynamic,以告诉编译器这些属性的实际定义在其他位置
    • ClassA+Render.m 中包含(#import)ClassA+Properties.h,这样所有属性都可以访问

    ClassA+Properties.h

    @interface ClassA (Properties)
    {
        @property NSUInteger property1;
        @property NSUInteger property2;
    }
    

    ClassA+Properties.m

    @interface ClassA (Properties)
    {
        @dynamic property1;
        @dynamic property2;
    }
    

    【讨论】:

    • 老实说,我早就放弃在 iOS 上使用 Objective-C 转而使用 C++11。话虽如此,我已经多次阅读了您的解决方案,虽然您可能已经为给出的简单示例找到了解决方案,但我不相信如果有 ClassA+Clear.m 投入其中,它仍然有效,由于多个匿名类别定义 (@interface ClassA ())。
    • 我在我的项目中使用过它,它有多个类别。 @interface ClassA () 用于 .m(多个)文件中,仅用于重新声明内容,它不会重新定义内容。因此,当链接器链接所有目标文件时,该方法将有一个定义。当您想在另一个类别中使用一个类别的方法时,只需在要使用的类别的.m文件中导入该类别的标题即可。
    • 你可以像前向声明或外部变量一样声明任意多次,只有一个定义(实现),所以没问题。
    【解决方案2】:

    您在ClassA 上声明了两个名为Render 的类别。这就是 Xcode 抱怨的原因。

    【讨论】:

    • 这就是它抱怨的原因,但是你能看到我想要完成的事情吗? Render 类别的定义之一仅包含公共方法,而Render 类别的另一个定义仅包含私有方法。我需要能够分离范围。如果他们必须全部公开或全部保密,这似乎是语言的一个弱点。
    • 我相信我看到了你的目标,并且我会分享你的希望,以避免仅仅为了限制范围而增加类别,但是为什么类别的私有方法需要在类别界面中可见全部?比如ClassA (Render)的私有方法需要在哪里可见?
    • 为什么Render的私有方法需要对所有ClassA可见?因为还有其他类别(例如,RenderSphere)使用类别Render 中的一些私有方法。换句话说,RenderSphere 可能需要调用privateConfigureBufferSpace 来了解其球形恶作剧。
    • 我明白了。那么我可能会说这些方法并不是真正的私有方法。或者困难可能是建议一个完全不同的替代方案,例如子类化。或者使用帮助类来处理跨类别的实现共性。
    • 在方便的地方,我确实应用了子类化和辅助类(我当然不会试图避免使用它们)但是在这种情况下我需要能够应用范围规则。在这种情况下,看起来最好的方法是为类别名称添加前缀:(PrivateRender)(Render)。幸运的是,这不会影响项目中的文件数量,但标题会稍微复杂一些(因为类别会是原来的两倍)。
    【解决方案3】:

    类别是一个概念,它表明任何新方法都可以添加到现有类中,并且所有子类最终都将获得该方法。

    您可以使用类别来定义现有类的其他方法——即使是你无法获得源代码的类——而无需子类化。您通常使用类别向现有类添加方法,例如在 Cocoa 框架中定义的类。 添加的方法由子类继承,在运行时与类的原始方法没有区别。

    如果您要添加私有方法,那么为什么要使用类别?因为它只能由该单个类文件本身使用。因此为什么不创建一个普通的私有方法!!!

    【讨论】:

    • 对于您从Apple Documentation on Categories 中省略的下一句:Using categories, you can also distribute the implementation of your own classes among several files.
    【解决方案4】:

    您可以在其自己的文件中的类扩展中声明 Render 的私有方法。这利用了您可以拥有多个类扩展的优势。

    ClassA.h:

    @interface ClassA : NSObject
    // public methods of ClassA
    @end
    

    ClassA+Render.h:

    @interface ClassA (Render)
    // public methods of category Render
    -(void)drawLine;
    -(void)drawCircle;
    @end
    

    ClassA+Render_Private.h:

    @interface ClassA ()
    // the private methods of the Render category.
    -(void)privateConfigureDeviceContext;
    -(void)privateConfigureBufferSpace;
    @end
    

    【讨论】:

    • 哎呀,我刚刚注意到我使用 RasterRender 作为单独的词,而它们本来是同一个词,我编辑了我的帖子来解决这个问题。在您的回答中,您将 ClassA+Raster.hClassA+Render.h 作为单独的文件 >.
    • 我担心我可能要做的是创建一个PrivateRender 类别和一个PublicRender 类别。但是,我有很多类别,这实际上会使这个数字翻倍。
    猜你喜欢
    • 2013-10-06
    • 1970-01-01
    • 2015-03-11
    • 1970-01-01
    • 2011-12-08
    • 2013-12-09
    • 1970-01-01
    • 2019-01-21
    相关资源
    最近更新 更多