分类(Category)
分类的作用:在不改变原来类的内容的基础上,为类增加一些方法。
使用注意:
1> 分类只能增加方法,不能增加成员变量
2> 分类方法实现中可以访问原来类中声明的成员变量
3> 分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,导致原方法无法使用。
4> 方法调用优先级:分类(最后参与编译的分类优先)-->原类-->父类
分类的写法
@interface Person : NSObject
@property NSString *name;
@property int age;
+ (void)run;
@end
@implementation Person
+ (void)run
{
NSLog(@"跑了一圈");
}
@end
// 为Person类添加分类Person1
@interface Person (Person1)
- (void)eat;
@end
@implementation Person (Person1)
- (void)eat
{
NSLog(@"吃了一顿");
}
@end
类的本质
类本身也是一个对象,是一个Class类型的对象,简称类对象
类对象的创建
int main()
{
Person *p = [[Person alloc] init];
// 调用分类的eat方法
[p eat];
p.name = @"jack";
p.age = 10;
// 创建类对象
Class c = [Person class];
// 使用类对象创建实例对象,类对象相当于类
Person *p2 = [[c alloc] init];
p2.name = @"rose";
p2.age = 15;
return 0;
}
创建了一个Person类的类对象,可以调用Person类的方法。
类的加载和初始化程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的load方法。 只调用一次
当程序使用某个类时,就会调用当前类的initialize方法
先加载父类,再加载子类(先调用父类的load方法,再调用子类的load方法)
先初始化父类,再初始化子类(先调用父类的initialize方法,再调用子类的initialize方法)
对象的输出
默认情况下,使用NSLog和%@输出对象时, 结果是:<类名:内存地址>
调用对象的description方法,将方法的返回值显示出来。description方法默认的返回值就是 类名:内存地址
@implementation Person (Person1)
- (void)eat
{
NSLog(@"吃了一顿");
}
// 重写原类的对象方法description,使其按照格式输出对象成员的值
-(NSString *)description
{
return [NSString stringWithFormat:@"name:%@,age:%d",_name,_age];
}
@end
如果想要使用NSLog和%@输出对象的所有属性值时,可以重写description方法来实现。
SEL消息机制
SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址,通过方法地址调用方法。每个方法都有一个对应的SEL类型的数据。
SEL对象的创建
int main()
{
Person *p = [[Person alloc] init];
// 调用分类的eat方法
[p eat];
p.name = @"jack";
p.age = 10;
// 创建类对象
Class c = [Person class];
// 使用类对象创建实例对象,类对象相当于类
Person *p2 = [[c alloc] init];
p2.name = @"rose";
p2.age = 15;
// 输出对象成员
NSLog(@"%@",p);
NSLog(@"%@",p2);
// 将run方法包装为SEL类型
SEL s = @selector(run);
// 调用Person类的run方法
[c performSelector:s];
return 0;
}
NSLog输出
__FILE__ : 源代码文件名
__LINE__ : NSLog代码所在行数
_cmd : 当前方法的SEL,即当前方法的地址。SEL数据无法直接打印,需要先转换为字符串
NSString *str = NSStringFromSelector(_cmd);