剖析Object-C中的属性与消息传递机制
来源:互联网 发布:mac os x 10.7.4 编辑:程序博客网 时间:2024/05/17 07:03
一、属性
属性是OC的一项特性,用于封装对象中的数据,OC对象通常会吧其所需要的数据保存为各种实例变量,实例变量一般都是通过存取方法来访问的。
例如有一个Person类,该类具有姓名和年龄等属性
#import <Foundation/Foundation.h>@interface Person : NSObject@property (nonatomic,assign) int age;@property (nonatomic,assign) NSString *name@end在OC中,实例变量(例如Person中的age)会被当作一种存储偏移量所用的特殊变量,所谓的偏移量就是硬编码,它表示该变量距离存放对象的内存区域的起始地址还有多远,OC会把该变量交由类对象(Person就是一个类对象)保管,偏移量会在运行期查找,这样做的好处就是如果类的定义变了,那么它存储的偏移量也会跟着改变,这样的话,无论何时访问实例变量,总能使用正确的偏移量,甚至是可以在运行期向类中新增实例变量,这就是稳固的应用程序二进制接口ABI,OC的这一特性主要是体现在分类或者是实现文件中定义实例变量。
二、消息传递
Object-C中,在对象之间传递数据并执行任务的过程就叫做消息传递,例如在Person类中有个setAge的方法,当我们创建一个对象并调用了setAge这个方法时,这个过程就是消息传递,setAge:是这个消息的名称,而10是这个消息的参数,两者结合起来称为消息
Person *p = [[Person alloc] init];[p setAge:10];我们知道, 在Object-c里消息是运行期绑定的,也就是说只有在运行时才知道有这个消息和它在内存中所在的位
置。如果向某个对象传递消息,那就会使用动态绑定机制来决定需要调用的方法,在底层,所有方法都是普通的C育秧函数,然而对象收到消息之后,究竟调用哪个方法完全取决于运行期,甚至是可以在程序运行时改变。
给对象发送消息可以这样来写:
id returnValue = [someObject messageName:parameter];
其中someObject是对象,也就是接收者,messageName叫selector,可以称之为“选择子”,编译器看到此消息后,将其转换为一条标准的C语言函数调用,所调用的函数乃是消息传递机制中的核心函数,叫做objc_msgSend,它的原型
如下:
voidobjc_msgSend(id self,SEL cmd,...)
这是个参数个数可变的函数,能接受两个或两个以上的参数,第一个参数代表接收者,第二个参数是SEL类型的选择
子,后续参数是消息中的参数。选择子指的就是方法的名字,编译器会把刚才哪个例子转换为如下函数
id returnValue = [someObject @selector(messageName:),parameter];
objc_msgSend函数会依据接收者与选择子的类型来调用适当的方法,为了完成此操作,该方法需要在接收者所属的类中搜寻其方法列表,如果能找到与选择子名称相符的方法,则跳至该其实现代码,若是找不到,那就沿着继承体系继续往上查找,等找到合适方法之后再跳转,如果最终还是找不到相符的方法,就会执行消息转发操作,转给系统的其他类来处理,如果再找不到相符合的方法,那就以程序崩溃告终。
消息传递机制虽然会经过许多步骤,但是objc_msgSend会将匹配结果缓存在快速映射表里面,每个类都有这样一块缓存,若是稍后还向该类发送与选择子相同的消息,那么执行起来就可以很快了。
利用这种特性,我们也可以来实现与java中反射一样的效果
代码示例:
#import <Foundation/Foundation.h>@interface Person : NSObject@property (nonatomic,assign) int age;- (Person *)initWithAge:(int)age;@end#import "Person.h"@implementation Person- (Person *)initWithAge:(int)age{ if (self = [super init]) { _age = age; } return self; }@end
#import "Person.h"@interface Student : Person@end#import "Student.h"@implementation Student@end
#import <Foundation/Foundation.h>#import "Person.h"#import "Student.h"int main(){ // 类的反射 Class name = NSClassFromString(@"Person"); Person *p = [[name alloc] init]; NSLog(@"%@",p); // 判断对象是不是属于指定类型或其子类 Student *stu = [[Student alloc] init]; if ([stu isKindOfClass:[Person class]]) { NSLog(@"%@是%@类型或子类",stu,[Person class]); } else { NSLog(@"%@不是%@类型或子类",stu,[Person class]); } // 判断对象是不是属于指定类型 if ([stu isMemberOfClass:[Person class]]) { NSLog(@"stu是Person类型"); } else { NSLog(@"stu不是Person类型"); } // 判断对象有没有某个方法 SEL sel = NSSelectorFromString(@"setAge"); if ([stu respondsToSelector:sel]) { NSLog(@"有该方法"); } else { NSLog(@"没有该方法"); } // 动态调用对象方法 Person *p1 = [[Person alloc] initWithAge:1]; NSNumber *age = [p1 performSelector:@selector(age)]; int age1 = [age intValue]; // Incompatible pointer to integer conversion initializing 'int' with an expression of type 'id' // 用‘id’类型的表达方法的不兼容的指针来转换初始化‘int’ NSLog(@"%d",age1); // 调用有参数的 Person *p2 = [[Person alloc] init]; [p2 performSelector:@selector(setAge:) withObject:@"2"]; NSLog(@"%d",p2.age); // 判断对象是否遵守某个协议 BOOL conforms = [p2 conformsToProtocol:@protocol(NSObject)]; NSLog(@"%d",conforms); return 0;}
参考资料:《Effective Object-C 2.0》
0 0
- 剖析Object-C中的属性与消息传递机制
- IOS开发笔记11-Object-C中的传递消息
- Objective c 中的消息传递机制
- 数据传递型情景下事件机制与消息机制的架构设计剖析(一)
- OGRE中的消息传递机制
- Object-C的消息传递机制和method swizzling方法混淆
- Object-c对象和消息传递
- Object-C 消息机制工作原理
- 深入理解Object-C消息转发机制
- 深入理解Object-C消息转发机制
- 深入理解Object-C消息转发机制
- Android中的消息机制:Handler消息传递机制
- Android中的消息机制:Handler消息传递机制
- 深度解析VC中的消息传递机制
- 深度解析VC中的消息传递机制
- 深度解析VC中的消息传递机制
- 深度解析VC中的消息传递机制
- 深度解析VC中的消息传递机制
- TTL传输中过期问题导致网站打不开
- 使用listview模拟微信列表界面
- 长连接和短连接
- Java编程思想重点笔记(Java开发必看)
- Confluence wiki 使用记录
- 剖析Object-C中的属性与消息传递机制
- vc++ External dependencies
- 周期串问题
- PostgreSQL性能优化综合案例讲解 - 1
- 禁止横竖屏切换;横竖屏切换不重启Activity;动态设置横竖屏
- struts2日期类型转换
- poj1704 Georgia and Bob
- scala隐式参数(implicit)
- 用ffmpeg编码aac