在介绍分类作用是什么之前,先看一下NSObject类的声明:
@interface NSObject <NSObject> {
Class isa;
}
+ (void)load;
+ (void)initialize;
- (id)init;
+ (id)new;
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;
- (void)finalize;
- (id)copy;
- (id)mutableCopy;
+ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ (Class)superclass;
+ (Class)class;
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
+ (BOOL)conformsToProtocol:(Protocol *)protocol;
- (IMP)methodForSelector:(SEL)aSelector;
+ (IMP)instanceMethodForSelector:(SEL)aSelector;
- (void)doesNotRecognizeSelector:(SEL)aSelector;
- (id)forwardingTargetForSelector:(SEL)aSelector NS_AVAILABLE(10_5, 2_0);
- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector;
- (BOOL)allowsWeakReference NS_UNAVAILABLE;
- (BOOL)retainWeakReference NS_UNAVAILABLE;
+ (NSString *)description;
+ (BOOL)isSubclassOfClass:(Class)aClass;
+ (BOOL)resolveClassMethod:(SEL)sel NS_AVAILABLE(10_5, 2_0);
+ (BOOL)resolveInstanceMethod:(SEL)sel NS_AVAILABLE(10_5, 2_0);
@end
@interface NSObject (NSCoderMethods) // < 1 >
+ (NSInteger)version;
+ (void)setVersion:(NSInteger)aVersion;
- (Class)classForCoder;
- (id)replacementObjectForCoder:(NSCoder *)aCoder;
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder NS_REPLACES_RECEIVER;
@end
// main.m
#import <Foundation/Foundation.h>
#import "NSString+WDL.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSLog(@"version = %ld",[NSObject version]);
}
return 0;
}
运行结果:
虽然在NSObject中没有version这个类方法,但是因为有< 1 >处的代码,NSObject就能调用version方法了,< 1 >处的写法就是分类。分类是指按照种类、等级或性质分别归类。分类的作用大致有以下3点:
1.通过分类可以使类的整体结构变得模块化,更加清晰
2.多人开发同一个类的情况下,使用分类可以避免文件更改的冲突
3.扩展某个类的功能以满足需求,比如NSString类,可以通过分类扩展逆序输出字符串等方法。
分类使用上需要注意的地方
1.分类只能用来增加方法,不能增加成员变量
2.分类方法的实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖原来的方法,导致原来的方法无法再使用,所以建议不要重新实现
4.方法调用的优先级: 分类(后编译的优先) > 原来类 > 父类
//
// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Person+Life.h"
#import "Person+Job.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Person *p = [[Person alloc] init];
// 原来类与两个分类都有breath,观察会调用哪个
[p breath];
// 生活分类的两个方法
[p eat];
[p sleep];
// 工作分类的两个方法 访问了原来类的成员变量
[p doCoder];
[p searchData];
}
return 0;
}
//
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,assign) int age;
// 呼吸
- (void) breath;
@end
//
// Person.m
#import "Person.h"
@implementation Person
// 呼吸
- (void) breath
{
NSLog(@"一呼一吸");
}
@end
//
// Person+Life.h
#import "Person.h"
@interface Person (Life)
// 吃饭
- (void) eat;
// 睡觉
- (void) sleep;
// 呼吸
- (void) breath;
@end
//
// Person+Life.m
#import "Person+Life.h"
@implementation Person (Life)
// 吃饭
- (void) eat
{
NSLog(@"吃饭");
}
// 睡觉
- (void) sleep
{
NSLog(@"睡觉");
}
// 呼吸
- (void) breath
{
NSLog(@"生活需要呼吸");
}
@end
//
// Person+Job.h
#import "Person.h"
@interface Person (Job)
// 敲代码
- (void) doCoder;
// 找资料
- (void) searchData;
// 呼吸
- (void) breath;
@end
//
// Person+Job.m
#import "Person+Job.h"
@implementation Person (Job)
// 敲代码
- (void) doCoder
{
NSLog(@"敲代码");
[self setAge:24]; // 设置年龄
}
// 找资料
- (void) searchData
{
NSLog(@"找资料");
NSLog(@"这个人多少岁:%d",[self age]);
}
// 呼吸
- (void) breath
{
NSLog(@"工作需要呼吸");
}
@end
运行结果:
看文件编译的先后
所以breath方法调用的是Life分类中的
最后的打印输出证明了分类方法可以直接访问原来类的成员变量
下面使用分类来扩展类NSString
// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Person+Life.h"
#import "Person+Job.h"
#import "NSString+Change.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = [NSString getReverseString:@"Welcome to beijing"];
NSLog(@"str逆序输出为:%@",str);
}
return 0;
}
// NSString+Change.h
#import <Foundation/Foundation.h>
@interface NSString (Change)
// OC字符串逆序输出
+(NSString *)getReverseString:(NSString *)str;
@end
//
// NSString+Change.m
#import "NSString+Change.h"
@implementation NSString (Change)
// OC字符串逆序输出
+(NSString *)getReverseString:(NSString *)str
{
NSMutableString *mstr = [NSMutableString stringWithString:str];
for (int i = 0; i < str.length / 2; i++)
{
// 声明两个NSRange变量,保存前后两边的一个字符
NSRange range1 = NSMakeRange(i, 1);
NSRange range2 = NSMakeRange(str.length - i - 1 ,1);
// 从左到右,依次取出字符串中的每个字符
NSString *subStr1 = [str substringWithRange:range1];
// 从右到左,依次取出字符串中的每个字符
NSString *subStr2 = [str substringWithRange:range2];
// 交换前后两个字符
[mstr replaceCharactersInRange:range1 withString:subStr2];
[mstr replaceCharactersInRange:range2 withString:subStr1];
}
return [NSString stringWithFormat:@"%@",mstr];
}
@end
运行结果:
分析:因为没有访问成员变量,所以写成了类方法,因为是依次从左与从右取出一个字符,然后进行交换,所以只要做字符串长度的一半的次数就好了