关于NSObject和运行时系统
类NSObject
OC作为一门动态编程语言,有很多动态的特性,OC不仅需要编译环境,还需要一个运行时系统(runtime system)来执行编译好的代码。运行时系统扮演的角色类似于OC的操作系统,它负责独立完成对象的生成,释放时的内存管理等。
程序中无法直接使用运行时系统提供的功能。根类方法中提供了运行时系统的基本功能,继承了NSObject的所有类都可以自由地使用运行时的功能,也就是说,根类相当于运行时系统的一个借口。
1.类和实例
NSObejct只有一个实例变量,就是Class类型的变量isa。isa用于标识实例对象属于哪个类对象。isa用于标识实例对象属于哪个类对象。因为isa决定着实例变量和类的关系,很重要,所以子类不可以修改isa的值。也不能直接通过访问isa来查询变量到底属于哪个类,而要通过实例方法class来完成查询。
NSObject的方法与其说是为自己定义的,不如说是为其子类和所有的实例对象而定义的。
-(Calss)class; 返回接受者所属类的类对象。
+(Class)class;返回类对象
-(id)self;返回接受者自身。是一个无任何实际动作但很有的方法。
-(Bool)isMemberOfClass:(Class)aClass; 判断消息接受者是不是参数aClass类的对象。
-(Bool)isKindOfClass:(Class)aClass判断消息接受者是否是aClass嘞或者是aClass类的子类的实例。这个和isMemberOfClass的区别在于当消息的接受者是aClass的子类的实例时也会返回YES;
-(Bool)isSubclassOfClass:(Class)aClass;判断消息接受者是不是参数aClass的子类或自身,如果是则返回YES
-(Class)superclass;返回消息接受者所在的父类的类对象;
+(Class)superclass;返回消息接受类的父类的类对象
2.实例对象的生成和释放
+(id)alloc;
-(void)dealloc;释放实例对象
-(oneway void)release;
-(id)retain;
-(id)autorelease;
-(NSUInterger)retainCount;
-(void)finalize;垃圾收集器在释放接受者对象之前会执行该finalize方法。
上面congdealloc到retainCount都是手动引用计数管理内存时调用的方法,使用ARC时不可用,finalize仅供垃圾回收有效时使用。
3.初始化
-(id)init
-(void)initialize;被用于类的初始化,也就是对类中共同使用的变量进行初始化,这个方法会在类收到第一个消息之前被自动调用,不能手动调用,而且只会被调用一次。
+(id)new;new是alloc和init 的组合。
4.对象的比较
-(Bool)isEqual:(id)anObject; 消息的接收者如果和参数anObject相等就返回YES
-(NSUinteger)hash;在把对象放入容器等的时候,返回系统内部用的散列值。【散列值相等的两个对象不一定相等,快速检索系统中一般都有散列表,OC的Foundation框架中也有用于计算散列的函数。数据存放的位置是由数据本身计算出来的散列值来决定的。及时内容相同的情况下,如果算出来的散列值不同,数据存放的位置也是不同的】
5.对象的内容描述
+(NSString *)description;返回一个NSSTring类型的字符串,表示消息接受者所属类的内容,通常都是这个类的类名。
-(NSString *)description;返回一个nsstring类型的字符串,表示消息接收者的实例对象的内容。通常是类名加id值,子类中也可以重新定义description的返回值。
6.关于消息发送机制
选择器和SEL类型
程序中的方法名(选择器)在编译后会被一个内部标识符所替代,这个内部标识符所对应的数据类型就是SEL类型。
OC为了能够在程序中操作编译后的选择器,定义了@selector()指令。通过使用@selector()指令就可以直接引用编译后的选择器。也可以生命SEL类型的变量。
选择器不同的情况下编译转化后生成的SEL类型的值也不一定想不同,相同的选择器所对应的SEL类型的值一定相同。
可以使用SEL类型的变量来发送消息,为此,NSObject准备了如下方法:
-(id)performSelector:(SEL)aSelector; 向消息的接收者发送aSelector代表的消息,返回这个消息执行的结果
-(id)performSelector:(SEL)aSelector withObject:(id)anObject;;向消息的接收者发送aSelector代表的信息,消息的参数为anObject,返回这个消息执行的结果
7.消息搜索
对象受到一个消息后会执行哪个方法是被动态决定的。所有的实例变量都存在一个Class类型isa变量,它就是类对象。当收到消息后,运行时系统会检查类内是否有和这个消息选择器相同的方法,如果有就执行对应的方法,如果没有就通过类对象中指向父类的指针来查找父类中是否有对应的方法。如果一直找到根类都没有找到对应的方法,就会提示执行错误。
如果每次收到消息都需要查找相应的方法的话,消息发送过程的开销就会很大。针对这种情况,运行时系统内部会缓存一个散列表,表中记录着某个类拥有和什么样的选择器对应的方法,方法被定义在何处等信息。这样一来,等下次再收到同样的消息时,直接利用上次缓存的信息即可,就不需要再重头进行搜索了。
NSObject中定义了可以动态查询一个对象是否能够相应某个选择器的方法。
-(Bool)respondsToSelector:(SEL)aSelector;查询消息的接受者中是否有能够相应aSelector的方法,包括从父类继承来的方法。如果存在的话,返回YES;
+(Bool)instancesResponToSelector:(SEL)aSelector;查询消息的接受者所属的类中是否有能够相应aSelector的实例方法,包括从父类继承来的方法,存在返回YES;
8.Xcode中的动作方法和Outlet的写法
开发环境Xcode及用于设计和测试的GUI的工具Interface Builder中,为了连接对象,在类的接口部分中声明了一些宏,通过这些宏变量能够将代码连接到nib。
动作方法的声明IBAction是一个宏,被定义为void。IBAction可以被理解为插座,可以通过outlet从空间中取出信息,或将新的信息赋值给空间。Outlet通常是一个类的实例变量。