【Objective-C】13-类和方法的本质
来源:互联网 发布:怎么查手机的网络制式 编辑:程序博客网 时间:2024/05/19 17:10
一、类的本质
1.1 类的本质是对象,是Class类型的对象,简称类对象。
1.2 类的创建过程:Person *p = [[Person alloc] init];
1>利用Class创建Person类对象;
2>利用Person类对象,创建Person类型的对象。
1.3 获取内存中类对象的两种方式
1> Class c = [p class]; //调用对象的class对象方法
2> Class c1 = [Person class]; //调用类的class类方法
1.4 利用上面两行代码获得的Class对象是同一个对象,指向的是同一个内存地址。可通过打印对象的内存地址验证。
1.5 类对象和类是同一个对象,所以可以通过类对象创建类的对象。
#import <Foundation/Foundation.h>@interface Person : NSObject+ (void)test;@end@implementation Person+ (void)test{NSLog(@"调用了test类方法");}@endint main() {//利用Person这个类创建了两个Person类型的对象Person *p = [[Person alloc] init];Person *p2 = [[Person alloc] init];Class c = [p class]; // 通过对象方法class获取内存中的类对象Class c2 = [Person class]; // 通过类方法class获取内存中的类对象NSLog(@"c=%p,c2=%p", c, c2); //打印两个类对象的内存地址,验证是否同一个对象。Class c3 = [p class];[c3 test]; //利用类对象调用类方法Person *p3 = [[c3 new] init]; // 利用类对象创建对象return 0;}
二、类的加载和初始化
2.1 当程序启动的时候,就会加载一次项目中所有的类和分类(不管程序运行过程中有没有用到这个类)。类被加载完毕的时候就会调用每个类和分类的+load方法。只会调用一次。
2.2 当第一次使用某个类的时候,就会调用一次当前类的+initialize方法。之后不管调用这个类多少次,整个项目生命周期中只会调用一次。
2.3 加载顺序:先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)。
先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)。
分类和类都实现+initialize方法,类的+initialize方法会被分类覆盖。
2.4 +initialize方法可以用来监听类,如果想在类第一次被使用时执行某些行为,可以把代码放在+initialize方法中。
#import <Foundation/Foundation.h>@interface Person : NSObject@end@implementation Person//当程序启动的时候,就会加载一次项目中所有的类。类被加载完毕的时候就会调用+load方法+ (void)load{NSLog(@"Person--load");}//当第一次使用这个类的时候,就会调用一次+initialize方法。整个项目生命周期中只会调用一次+(void)initialize{NSLog(@"Person--initialize");}@end@interface Student : Person@end@implementation Student//在类被加载的时候调用+ (void)load{NSLog(@"Student--load");}+(void)initialize{NSLog(@"Student--initialize");}@end@interface Person(MM)@end@implementation Person(MM)//在类被加载的时候调用+ (void)load{NSLog(@"Person (MM)--load");}// 使用类时会分类会覆盖原来类的+initialize方法+(void)initialize{NSLog(@"Person (MM)--initialize");}@endint main() {Person *p = [[Person alloc] init];Person *p2 = [[Person alloc] init];Student *s = [[Student alloc] init];return 0;}输出结果:
2015 - 02 - 08 05:28 : 31.400 04 - 类的加载[1465:46788] Person--load
2015 - 02 - 08 05 : 28 : 31.401 04 - 类的加载[1465:46788] Student--load
2015 - 02 - 08 05 : 28 : 31.401 04 - 类的加载[1465:46788] Person(MM)--load
2015 - 02 - 08 05 : 28 : 31.402 04 - 类的加载[1465:46788] Person(MM)--initialize
2015 - 02 - 08 05 : 28 : 31.402 04 - 类的加载[1465:46788] Student--initialize
三、description方法
description方法分对象方法和类方法。默认使用NSLog和%@打印对象时,直接就输出对象的类名和内存地址。默认使用NSLog和%@打印类时,直接就输出类名。当需要显示自定义信息时,需要重写description方法。
3.1 -description
默认情况下,利用NSLog和%@(NSLog(@"%@",p);)输出对象时,结果是:<类名:内存地址>
1>会调用对象p的-description方法
2>拿到-description方法的返回值(NSString *)显示到屏幕上
3>-description方法默认返回的是“类名+内存地址”
4>决定了实例对象的输出结果
5>-description的重写
- (NSString *)description
{
//下面代码会引发死循环
// NSLog(@"%@",self);
return [NSString stringWithFormat:@"age=%d,name=%@",_age,_name];
}
3.2 +description
Class c = [Person class];
默认情况下,利用NSLog和%@(NSLog(@"%@",c);)输出类对象时,结果是:类名
1>会调用类的+description方法
2>拿到+description方法的返回值(NSString *)显示到屏幕上
3>决定了类对象的输出结果
NSLog(@"%@",c);
4>+description的重写
+(NSString *)description
{
return @"ABC";
}
#import <Foundation/Foundation.h>@interface Person : NSObject@property int age;@end@implementation Person// 重写-description方法- (NSString *)description{return[NSString stringWithFormat : @"age=%d", _age];}// 重写+descrition方法+(NSString *)description{return @"调用+description";}@endint main() {Person *p = [[Person alloc] init];NSLog(@"%@", p);//调用-descriptionClass c = [Person class];NSLog(@"%@", c);return 0;}输出结果:
2015 - 02 - 08 06:06 : 49.832 05 - description[1582:51889] age = 0
2015 - 02 - 08 06 : 06 : 49.834 05 - description[1582:51889] 调用+description
四、NSLog方法补充:
NSLog(@"%p", &p); // 指针变量的地址
NSLog(@"%p", p); // 对象的地址
NSLog(@"%@", p); // <类名:对象地址>
NSLog(@"%d", __LINE__); // 打印行号
//NSLog(@"%s",__FILE__); //NSLog输出C语言字符串的时候,不能有中文
printf("%s\n", __FILE__);
NSLog(@"%s", __func__); //输出当前函数名
五、SEL
5.1 SEL是一种数据类型,全称Selector,表示方法的存储位置。
5.2 方法调用的本质:SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法。其实消息就是SEL。
Person *p = [[Person alloc] init];
[p test];
1.把test包装成SEL类型的数据
2.根据SEL数据找到对应的方法地址
3.根据方法地址调用对应的方法
4.以上三个步骤会有缓存机制,当第一次通过SEL找到相对应的方法时,会把该查询结果缓存起来,便于下次的查找。
5.3 通过SEL间接调用方法
间接调用test方法
1>无参数
[p performSelector : @selector(test2)];
2>有参数
[p test : @"123"];
[p performSelector : @selector(test:) withObject:@"456"];
5.4 方法的存储位置
1>每个类的方法列表都存储在类对象中
2>每个方法都有一个与之对应的SEL类型的对象
3>根据一个SEL对象就可以找到方法的地址,进而调用方法
4>SEL类型的定义
typedef struct objc_selector *SEL;
5.5 SEL对象的创建
SEL s = @selector(test);
SEL s2 = NSSelectorFromString(@"test");
5.5 知道方法名的字符串,调用方法
NSString *name = @"test2";
SEL s = NSSelectorFromString(name);
[p performSelector: s];
5.6 _cmd
每个方法内部都包含着一个_cmd,代表着当前方法。如果要打印出来的话,需要调用NSStringFromSelector(_cmd);
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"%@", str);
5.7 注意
在方法内部调用下面语句会引发死循环
[self performSelector : _cmd];
#import <Foundation/Foundation.h>@interface Person : NSObject+ (void)test;-(void)test2;-(void)test3:(NSString *)str;@end@implementation Person+ (void)test{NSLog(@"+test");}-(void)test2{NSString *str = NSStringFromSelector(_cmd);NSLog(@"调用了test2方法---%@", str);//会引发死循环//[self performSelector:_cmd];}-(void)test3:(NSString *)str{NSLog(@"test3---%@", str);}@endint main() {Person *p = [[Person alloc] init];NSString *name = @"test2";SEL s = NSSelectorFromString(name);[p performSelector : s];[p performSelector : @selector(test2)];SEL s2 = @selector(test3:);//间接调用带参数的方法,别忘了方法后面的冒号,因为冒号也是属于方法名的一部分[p performSelector : s2 withObject : @"hhh"];return 0;}
输出结果:
2015-02-08 07:42:12.070 SEL[1725:61095] 调用了test2方法---test2
2015-02-08 07:42:12.072 SEL[1725:61095] 调用了test2方法---test2
2015-02-08 07:42:12.072 SEL[1725:61095] test3---hhh
- 【Objective-C】13-类和方法的本质
- Objective-C -类的本质
- Objective-c - 继承的本质, new方法
- 黑马程序员---Objective-C 类的本质
- Objective-C——类的本质
- 【Objective-C学习笔记】核心语法——类的本质、description方法
- objective-c中类的本质与description
- Objective - C基础: 第四天 - 6.类的本质
- Objective-C - 封装的本质与细节
- Objective-C获取类方法和实例方法的IMP
- [objective-c]教程一-----objective-c 类和方法
- Objective C类方法load和initialize的区别
- Objective C类方法load和initialize的区别
- Objective C类方法load和initialize的区别
- Objective C类方法load和initialize的区别
- Objective C类方法load和initialize的区别
- 1.Objective C类方法load和initialize的区别
- Objective-C 类属性和方法的访问权限
- linux 查看系统版本
- 对UTF-8和GB2312格式 URL进行解码
- hdu2059--龟兔赛跑(dp)
- 第40天: UDAF函数 A 的意思 aggregation 聚集
- 「数字信号处理」课程设计--练习题
- 【Objective-C】13-类和方法的本质
- HDU -- 4786 Fibonacci Tree (mst)
- dramsim2地址映射
- 支付机构AID汇总
- Java中文乱码之一 文件编码与系统环境
- Leetcode_Valid Palindrome
- eclipse Maven构建的工程无法发布lib到tomcat的解决方法
- shell编程表达式求值
- ACM--steps--3.1.6--Tiling_easy version