【问题标题】:Difference between Category and Class Extension?类别和类扩展之间的区别?
【发布时间】:2011-03-30 19:21:38
【问题描述】:

类别和类扩展有什么区别。我相信两者都用于在现有类中添加自定义方法。有人可以解释一下吗?非常感谢您使用代码进行示例。

【问题讨论】:

标签: objective-c


【解决方案1】:

类别和扩展

类别允许您将方法添加到现有类——甚至是您没有源代码的类。类别是一个强大的功能,它允许您扩展现有类的功能而无需子类化。使用类别,您还可以在多个文件中分发您自己的类的实现。类扩展类似,但允许在主类 @interface 块内以外的位置为类声明额外的必需 API。

向类添加方法

您可以通过在接口文件中以类别名称声明它们并在实现文件中以相同名称定义它们来向类添加方法。类别名称表明这些方法是对在别处声明的类的添加,而不是新类。但是,您不能使用类别向类添加其他实例变量。

类别添加的方法成为类类型的一部分。例如,添加到类别中的 NSArray 类的方法被包含为编译器期望 NSArray 实例在其曲目中具有的方法。但是,在子类中添加到 NSArray 类的方法不包含在 NSArray 类型中。 (这只对静态类型的对象很重要,因为静态类型是编译器知道对象类的唯一方法。)

类别方法可以做任何在类中定义的方法可以做的事情。在运行时,没有区别。类别添加到类的方法被该类的所有子类继承,就像其他方法一样。

类别接口的声明看起来很像类接口声明——除了类别名称列在类名称之后的括号内,并且没有提及超类。除非其方法不访问该类的任何实例变量,否则该类别必须为其扩展的类导入接口文件:

#import "ClassName.h"
 
@interface ClassName ( CategoryName )
// method declarations
@end

请注意,类别不能为该类声明额外的实例变量;它只包括方法。但是,类范围内的所有实例变量也在类范围内。这包括类声明的所有实例变量,甚至是声明的@private

可以添加到类中的类别数量没有限制,但每个类别名称必须不同,并且每个类别都应声明和定义一组不同的方法。

扩展

类扩展类似于匿名类别,只是它们声明的方法必须在相应类的主 @implementation 块中实现。使用 Clang/LLVM 2.0 编译器,您还可以在类扩展中声明属性和实例变量。

类扩展的一个常见用途是将公开声明为只读的属性重新声明为私有的 readwrite:

@interface MyClass : NSObject
@property (retain, readonly) float value;
@end
 
// Private extension, typically hidden in the main implementation file.
@interface MyClass ()
@property (retain, readwrite) float value;
@end

// Notice that (in contrast to a category) no name is given in the parentheses in the second @interface block.

一个类通常也有一个公开声明的 API,然后有其他方法私下声明,供该类或该类所在的框架单独使用。类扩展允许您在主类 @interface 块以外的位置为类声明额外的必需方法,如下例所示:

@interface MyClass : NSObject
- (float)value;
@end
 
 
@interface MyClass () {
    float value;
}
- (void)setValue:(float)newValue;
@end
 
@implementation MyClass
 
- (float)value {
    return value;
}
 
- (void)setValue:(float)newValue {
    value = newValue;
}
 
@end

setValue: 方法的实现必须出现在类的主 @implementation 块中(您不能在类别中实现它)。如果不是这种情况,编译器会发出一条警告,指出它找不到 setValue: 的方法定义。 如需官方文档,请点击此链接:source

【讨论】:

    【解决方案2】:
    1. 类别

    => 在 Objective C 中,当您想在没有继承的情况下为类添加更多功能时,只需使用 category 即可。

    => 它带有自己的 .h.m 文件

    => Category 用于添加新方法而不是属性。

    1. 类扩展
    -> In Objective C, when you want to make behaviour of some property private you use class extension.
    
    -> it comes with **.h** file only.
    
    -> mainly for properties.
    

    注意:当我们添加一个新文件并选择objective c的一个选项时 类别显示类别和“类别”而不是“子类”所以它 显示像

    @interface className (categoryName)
    @end
    

    -你会得到两个文件.h.m,文件名为(className+categoryName.hclassName +categoryName.m)

    在扩展的情况下你会得到

    @interface className()
    @end
    

    -您只会得到一个名为 className_extensionName.h

    的文件
    • 在类别中你不拥有类,但在扩展中你是。

    【讨论】:

    • @Prasanna:类扩展名仅包含在 .m 文件中,而不包含在 .h 中
    • 类扩展名仅带有一个 .h 文件,而不是一个 .m
    【解决方案3】:
    1. 类别是一种向类添加方法的方法,无论源代码是否可用,这意味着您可以将类别添加到NSString 等基础类以及您自己的自定义类中。

      扩展只能添加到源代码可用的类,因为编译器同时编译源代码和扩展。

    2. 我们可以在类扩展中添加额外的实例变量和属性,但不能在类别中。

    3. 扩展中的任何变量和方法甚至都不能被继承的类访问。

    4. 类别和扩展基本上都是为了处理大型代码库,但类别是在多个源文件中扩展类 API 的一种方式,而扩展是在主接口文件之外添加所需方法的一种方式。

    5. 当你必须将相同的类代码根据不同的功能分解成不同的源文件时使用类别,当你只需要在主界面文件之外的现有类中添加一些必需的方法时使用扩展。 此外,当您需要修改类中公开声明的实例变量时,例如, readonly 到 readwrite,你可以在 extension 中重新声明。

    【讨论】:

    • 我读了 5 个类似的问题,有很多答案,这是最好的。谢谢!
    • 您也可以在类别中添加属性。请参阅@Pebby 答案。
    • 为什么 - 扩展中的任何变量和方法甚至不能被继承的类访问。?可以详细说明一下吗?
    【解决方案4】:

    扩展:将方法设为私有并添加我们自己的自定义类的属性,而不是 Apple 类的属性。

    类别:要在现有类中添加更多方法而不是属性,它可以用于自定义类和 Apple 类,如NSString

    【讨论】:

    • 简洁优雅。坚持下去
    【解决方案5】:

    这是我的理解:

    扩展通常用于向我们自己的“自定义类”添加额外的功能。我们可以添加私有方法或扩展类接口的属性,这些接口可以在类的实现中使用。

    扩展将被写入与类相同的文件中。因此,您不能为 String、Float 等预定义类型编写扩展。

    另一方面,类别可用于向预先存在的类添加额外的方法。例如,我们可以通过扩展 String 类来创建自己的方法。请注意,我们无法在类别中创建额外的属性。类别的另一个主要优点是我们可以将类别写入任何其他文件中,在您的类退出的文件之外。

    此外,在创建类别时,您应该在括号内为其命名。 但是对于扩展名,不需要名称。因此,有时它们也被称为匿名类别。

    【讨论】:

    【解决方案6】:

    类别

    当您创建包含大量方法的文件时使用类别。因此它们为您提供将单个类分解为不同模块的工具。此外,如果对类别进行任何更改,编译器不会浪费时间进行编译整个项目。类别无法添加新变量或属性并查看其父类。您可以覆盖类别中的方法,但这不是一个好主意,因为该方法不能进一步被覆盖。也可以影响流程,因为所有类别都具有相同的层次结构,因此在运行时可能存在属于同一父类的两个类别。也可以使用类别创建受保护的方法

    扩展

    扩展使您能够覆盖属性或向现有父类添加新属性。与它们没有名称的类别在语法上相同,并表示为@interface class() 没有 .m 文件,扩展中声明的方法必须在父文件的@implementation 中实现

    更多帮助请访问this 链接

    【讨论】:

      【解决方案7】:

      类似c#、java抽象类或接口的ios扩展
      ios类类似c#,java类扩展

      【讨论】:

      • 你的回答就像“猫似虎,回答瞎子”。大声笑
      • 实际上并非如此。懂c#或者java的都是最直接最快速的解释。
      • 完全不是描述性的,几乎没有回答这个问题。
      【解决方案8】:

      我们还可以在类别类中使用设置关联属性来设置属性。

      @interface SomeClass (Private)
      
      @property (nonatomic, assign) id newProperty;
      
      @end
      
      NSString * const kNewPropertyKey = @"kNewPropertyKey";
      
      @implementation SomeClass (Private)
      
      @dynamic newProperty;
      
      - (void)setNewProperty:(id)aObject
      {
          objc_setAssociatedObject(self, kNewPropertyKey, aObject, OBJC_ASSOCIATION_ASSIGN);
      }
      
      - (id)newProperty
      {
          return objc_getAssociatedObject(self, kNewPropertyKey);
      }
      
      @end
      

      参考:http://inchoo.net/dev-talk/ios-development/how-to-add-a-property-via-class-category/

      【讨论】:

        【解决方案9】:
        @interface SomeClass ()
        
        
        - (void) anAdditionalMethod;
        
        
        @end
        

        我认为这不是声明类别的方式。 类别必须有名称

        @interface SomeClass (XYZ)
        
        
        - (void) anAdditionalMethod;
        
        
        @end
        

        例如

        @interface NSMutableArray (NSMutableArrayCreation)
        
        + (id)arrayWithCapacity:(NSUInteger)numItems;
        - (id)initWithCapacity:(NSUInteger)numItems;
        
        @end
        

        Apple 为 NSMutableArray 声明

        【讨论】:

        • 这是你声明和扩展的方式,不是一个类别-> @interface SomeClass ()
        【解决方案10】:

        类别是向现有类添加方法的一种方式。它们通常驻留在名为“Class+CategoryName.h”的文件中,例如“NSView+CustomAdditions.h”(当然还有 .m)。

        类扩展是一个类别,除了两个主要区别:

        1. 该类别没有名称。它是这样声明的:

          @interface SomeClass ()
          
          
          - (void) anAdditionalMethod;
          
          @end
        2. 扩展的实现必须在文件的主@implementation块中。

        在 .m 文件的顶部看到一个类扩展来声明该类的更多方法是很常见的,然后在该类的主要 @implementation 部分中实现这些方法。这是一种声明“伪私有”方法的方式(伪私有,因为它们不是真正的私有,只是没有对外暴露)。

        【讨论】:

        • 在 Class-Extensiosn 中,您可以将(公共)只读属性中的属性覆盖为内部读写。从 LLVM 1.5 开始,您可以做更多事情:您现在可以在类扩展中声明实例变量,这样它们就可以从常规接口中消失。
        • 既然可以在类中直接实现这些方法和属性,为什么还要添加类扩展?对我来说似乎有点多余。
        • @user1721803 正如 Dave 所建议的,您可能希望保留一些未公开的属性/方法。这是使用扩展的时候。考虑一个视图,您可以将所有 IBOutlets 和 IBActions 连接到扩展中,并公开允许初始化/更新 Outlets 和 Actions 的方法。
        • @MaxSeelemann 你能演示一下如何通过一个简短的脚本使“一个(公共)只读属性在内部可读写”吗?谢谢。
        • This answer 声明“Class+CategoryName.swift”文件中的扩展名,是否正确??
        猜你喜欢
        • 2017-09-29
        • 2014-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-18
        • 1970-01-01
        • 2012-09-02
        • 2019-03-09
        相关资源
        最近更新 更多