【问题标题】:Why Does This Category Work? Category vs. Class Extension为什么这个类别有效?类别与类扩展
【发布时间】:2012-09-20 18:38:50
【问题描述】:

这是我在我的一个类的实现文件中的内容...

代码设置 #1

@interface MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController
- (void)viewDidLoad
{
    NSString *myString = [self myPrivateMethod];
    NSLog(@"%@", myString);
}

- (NSString *)myPrivateMethod
{
    return @"someString";
}
@end

使用此代码,一切正常,并记录“someString”。

但是我的代码不应该以某种方式看起来不同吗?我实际上是偶然使用该类别的(我复制/粘贴了一些东西,但没有注意到“PrivateMethods”在那里;我的意思是使用类扩展)。

我的代码不应该看起来像以下之一吗:

代码设置 #2

@interface MyViewController ()
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController
....

或者:

代码设置 #3

@interface MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController (PrivateMethods)
....

在这种情况下发生的事情背后有哪些细微差别?代码设置 #1 与代码设置 #2 有何不同?

编辑:关于设置 #3 的问题

这样设置有什么作用?这甚至会“工作”吗?

@interface MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod;
@end

@implementation MyViewController
- (void)viewDidLoad
{
    NSString *myString = [self myPrivateMethod];
    NSLog(@"%@", myString);
}
@end

@implementation MyViewController (PrivateMethods)
- (NSString *)myPrivateMethod
{
    return @"someString";
}
@end

【问题讨论】:

    标签: objective-c categories class-extensions


    【解决方案1】:

    选择器只是在运行时被推送到同一个平面命名空间中。编译器没有添加额外的代码来区分选择器是在一个类别中定义的方法(当消息传递时)——它都是平面的。

    类别的符号以不同的方式导出,但这对于加载后的运行时并不重要。

    您通常应该使用设置#3:如果在一个类别中声明了一个方法,则它应该在该类别的@implementation 中定义。编译器偶尔会救你,它是一个更纯粹的结构。 (当然,不是每个方法都属于一个类别)。同样,@interface 中的声明应该定义在对应的@implementation 中,类延续(@interface MONClass ())中的声明定义也应该出现在主@implementation 中:

    @implementation MONClass
    // add your @interface MONClass definitions here
    // also add your @interface MONClass () definitions here
    @end
    

    更新问题

    是的,那会很好。您需要做的就是#import 包含@interface MyViewController (PrivateMethods) 的标头。我实际上在某些课程中这样做是为了按主题分类/组织。

    通常,“私有方法”在类延续中声明,但没有必要这样做(ivars/properties OTOH…)。

    【讨论】:

    • 用另一个关于设置 #3 的问题更新我的问题。到目前为止,谢谢!
    • 我相信在这种情况下,(最近的)Clang 会将一个未声明的方法的定义视为同一 @implementation 的声明,这一点也很重要。
    • @MikeS:我不确定它从哪个编译器版本开始。不过,它已经出现了一些 Xcode v。至少从 4.2 开始。
    • @JoshCaswell 是的,好点(+1)。 clang 现在支持解析整个 @implementation 范围。以前,这是可能的,但限制是定义需要先于选择器的使用。因为每个@implementation 块都必须关闭,这是一个很好的补充。
    • 哦,对了,只是排序不再重要了。
    猜你喜欢
    • 2011-10-31
    • 1970-01-01
    • 2011-09-25
    • 2020-10-06
    • 1970-01-01
    • 2019-07-19
    • 2015-07-26
    • 2018-09-21
    相关资源
    最近更新 更多