ObjectiveC-10-OOP面向对象程序设计-分类/类别

类别(Category)是OjectiveC的一个特性,主要目的是让开发者可以以模块的形式向类添加方法(扩展),创建标准化的方法列表供给其他人实现。

有些文档也会翻译成类别,其实是一个意思。

概述

语法说明

类别提供了一个简单的方式,将类定义模块化到相关组或分类中,同时也提供了扩展现有类定义的简便方式。换句话说,它的功能有些类似于接口继承,但又比继承简单和强大,在使用时需要结合继承一起使用,其能力是非常厉害的。 分类的语法如下:

objectivec 复制代码
@interface Fraction(Category1) //类名+(类别名称)
 //分类方法的代码
@end
@interface Fraction(Category2)
 //分类方法的代码
@end

类别的作用

如果在xcode中使用新建文件功能创建Cocoa class文件,会自动生成.h和.m文件。在这种分离的设计基础上附加分类后,可以使用分类实现下面三个方面的能力增强:

  1. 扩展现有类库的功能:比如扩展NSString、NSObject类,这种方式某些书中扩展NSObject类有时被称为非正式协议;
  2. 扩展现有类的声明:定义一个声明,然后分模块实现,比如在一个.h文件中定义类声明,然后分多个.m实现,一个.m实现其中一个分类,这样方便分工合作;
  3. 为现在的自定义类添加私有方法而不必重新定义子类;

类别规则

  1. 类别文件名称一般是是"类名称+类别名称"来命名,这是一个不成文的规定;
  2. 类别中可以添加属性,但不能添加实例变量,而且属性必须是@dynamic类型的;
  3. 如果类别方法与现有类的方法重名,类的方法会被覆盖掉,一旦覆写后外部就不能访问原来的方法了,所以这块要特殊设计一下;
  4. 如果多个分类中有同名的方法,可能会引起混乱;分类后不仅会影响当前类,也会影响所有的子类;
  5. 类别的名称是在类的范围内是唯一的;

创建类别

在新建文件中,选择Objective-C文件类型

在配置界面做如下配置,注意File Type选择 Category:

最后生成如下项目工程文件如下:

类别能力

给现有类添加新方法

类别可以为所有类添加新方法,包括系统类库和自定义的类。下面的代码就用一个自定义的类别来扩展系统提供的NSString类库的功能。

  • 类别定义
objectivec 复制代码
//扩展系统NSString,添加一个名为NumberConvenience的类别
#import <Foundation/Foundation.h>

@interface NSString (NumberConvenience)

- (NSNumber *)lengthAsNumber; //添加一个新方法

@end
  • 类别实现
objectivec 复制代码
#import "NSString+NumberConvenience.h"

@implementation NSString (NumberConvenience)

- (NSNumber *)lengthAsNumber{
    NSUInteger length = [self length];
    return ([NSNumber numberWithUnsignedInt:length]);
} // lengthAsNumber

@end
  • 类别测试
objectivec 复制代码
#import <Foundation/Foundation.h>
#import "NSString+NumberConvenience.h"

int main(int argc, const char * argv[]){
    @autoreleasepool
    {
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setObject:[@"hello" lengthAsNumber] forKey:@"hello"];
        NSLog (@"%@", dict);
    }
    return 0;
}

类能力(声明)的动态扩展

有别于上面的给现有类添加新方法的实现,类功能的动态扩展不需要新建文件,也可以实现定义实例变量。

方法是创建一个未命名的分类,然后在()中不指定任何名字,在这个类中可以扩展实例变量和属性(在有命名的分类中是不允许的)。未命名分类中的方法需要在主实现区中实现,而不是在分离的实现区中实现。

在未命名类别中的扩展的属性必须是私有的

  • 自定义类,Fraction是一个自定义的类,用于此示例的测试
objectivec 复制代码
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

//原始接口声明
@interface Fraction : NSObject

@property (assign) NSInteger thing1;
//标记为只读属性
@property (readonly, assign) NSInteger thing2;

- (void)resetAllValues;

@end
  • 扩展自定义类的属性和方法
objectivec 复制代码
@interface Fraction() //空
NS_ASSUME_NONNULL_END
{
    NSInteger thing4; //添加了新实例变量
}
@property (readwrite, assign) NSInteger thing2; //覆盖了原有属性
@property (assign) NSInteger thing3; //添加了新私有属性
@end
  • 实现自定义类
objectivec 复制代码
#import "Fraction.h"

@implementation Fraction

- (void)resetAllValues
{
    self.thing1 = 200;
    self.thing2 = 300;
    self.thing3 = 400;
    thing4 = 5;
}

- (NSString *) description
{
    NSString *desc = [NSString stringWithFormat: @"%d %d %d %d", _thing1, _thing2, _thing3, thing4];
    
    return (desc);
    
} // description

@end
  • 测试代码
objectivec 复制代码
#import <Foundation/Foundation.h>
#import "NSString+NumberConvenience.h"
#import "Fraction.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        
        [dict setObject:[@"hello" lengthAsNumber] forKey:@"hello"];
        
        NSLog (@"%@", dict);
        
        
        Fraction *things = [[Fraction alloc] init];
        things.thing1 = 1;
        NSLog(@"%@", things); //~1 0 0 0
         
        //重新赋值
        [things resetAllValues];
        NSLog(@"%@", things); //~200 300 400 5
    }
    return 0;
}

类分文件实现

前面所有的代码实现全是一个.h,一个m。如果是大型项目的话.m中的代码量可能非常区大,这里可以采用两种不同的设计方案解决:拆类或是分类。除了代码整洁外,还可以多人协作以及实现代码分包存储等功能,打破了继承这种约束。

即定义一个.h,多个.m实现这样的模式来分散类的实现,每个.m实现一个类别接口,示例代码如下:

类别定义

objectivec 复制代码
//类别定义
#import <Foundation/Foundation.h>

@interface CategoryThing : NSObject
{
  NSInteger thing1;
  NSInteger thing2;
  NSInteger thing3;
}
@end // CategoryThing

// Category thing1
@interface CategoryThing (Thing1)
- (void)setThing1:(NSInteger)thing1;
- (NSInteger)thing1;
@end

// Category thing2
@interface CategoryThing(Thing2)
- (void)setThing2:(NSInteger)thing2;
- (NSInteger)thing2;
@end // CategoryThing (Thing2)

// Category thing3
@interface CategoryThing (Thing3)
- (void)setThing3:(NSInteger)thing3;
- (NSInteger)thing3;
@end // CategoryThing (Thing3)

类别实现

objectivec 复制代码
#import "CategoryThing.h"

@implementation CategoryThing (Thing1)
- (void)setThing1:(NSInteger)t1{
    thing1 = t1;
}

- (NSInteger) thing1{
    return (thing1);
}

@end // CategoryThing
objectivec 复制代码
#import "CategoryThing.h"

@implementation CategoryThing (Thing2)

- (void)setThing2:(NSInteger) t2{
    thing2 = t2;
}

- (NSInteger)thing2{
    return (thing2);
}

@end 
objectivec 复制代码
\#import "CategoryThing.h"

@implementation CategoryThing (Thing3)

- (void)setThing3:(NSInteger) t3{
    thing3 = t3;
}

- (NSInteger)thing3{
    return (thing3);
}

@end 

程序测试

main测试

objectivec 复制代码
#import <Foundation/Foundation.h>
#import "CategoryThing.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        CategoryThing *thing = [[CategoryThing alloc] init];
        
        [thing setThing1: 5];
        [thing setThing2: 23];
        [thing setThing3: 42];
        
        NSLog (@"Things are %@", thing); //Things are 5 23 42
    }
    return 0;
}

end...

相关推荐
程序猿看视界39 分钟前
如何在 UniApp 中实现 iOS 版本更新检测
ios·uniapp·版本更新
panpantt3211 小时前
【参会邀请】第二届大数据与数据挖掘国际会议(BDDM 2024)邀您相聚江城!
大数据·人工智能·数据挖掘
statistican_ABin2 小时前
R语言数据分析案例45-全国汽车销售数据分析(可视化与回归分析)
数据挖掘·数据分析
endingCode3 小时前
45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
javascript·macos·typescript
CV学术叫叫兽3 小时前
快速图像识别:落叶植物叶片分类
人工智能·分类·数据挖掘
网络真危险!!3 小时前
【数据分析】认清、明确
数据挖掘·数据分析
菜鸟学Python3 小时前
Python 数据分析核心库大全!
开发语言·python·数据挖掘·数据分析
dr李四维4 小时前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
️ 邪神4 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
CV学术叫叫兽5 小时前
一站式学习:害虫识别与分类图像分割
学习·分类·数据挖掘