Effective Objective-C 2.0 学习记录(二)

来源:互联网 发布:java get 中文乱码 编辑:程序博客网 时间:2024/06/06 10:57

Effective Objective-C 2.0 学习记录(一)

八、黑魔法(Method Swizzling)
在runtime时,可以向类中新增或替换选择器所对应的方法实现。这种方法不宜滥用。
用到的相关方法:

   method class_getInstanceMethod(Class aClass, SEL aSelector) //返回aClass的名为aSelector的方法 //如果 swizzling 的是类方法, 采用如下的方式:  Class class = object_getClass((id)self);         ...  Method originalMethod = class_getClassMethod(class, originalSelector);  Method swizzledMethod = class_getClassMethod(class, swizzlingSelector);//添加新方法class_addMethod(,函数指针,对当前函数编码) BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)    /*    参数说明:    cls:被添加方法的类    name:可以理解为方法名,    imp:实现这个方法的函数    types:一个定义该函数返回值类型和参数类型的字符串    */class_addMethod([EmptyClass class], @selector(say:), (IMP)say, "i@:@");    /*    其中types参数为"i@:@“,按顺序分别表示:    i:返回值类型int,若是v则表示void    @:参数id(self)    ::SEL(_cmd)    */

九、类对象

//每个结构体的首个成员是Class类的变量,该变量定义了对象所属的类,通常称为“is a”指针struct objc_object {    Class isa  OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;//此结构体存放类的“元数据”typedef struct objc_class *Class;struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;//每个Class都有一个isa指针#if !__OBJC2__    Class super_class     //本类的父类                                   OBJC2_UNAVAILABLE;    const char *name              //类名                           OBJC2_UNAVAILABLE;    long version                      //类版本                       OBJC2_UNAVAILABLE;    long info                                                OBJC2_UNAVAILABLE;//!*!供运行期使用的一些位标识。如:CLS_CLASS (0x1L)表示该类为普通class; CLS_META(0x2L)表示该类为metaclass等(runtime.h中有详细列出)    long instance_size          //实例大小                             OBJC2_UNAVAILABLE;    struct objc_ivar_list *ivars      //存储每个实例变量的内存地址    OBJC2_UNAVAILABLE;    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;//!*!根据info的信息确定是类还是实例,运行什么函数方法等    struct objc_cache *cache      //缓存                           OBJC2_UNAVAILABLE;    struct objc_protocol_list *protocols     //协议                OBJC2_UNAVAILABLE;#endif} OBJC2_UNAVAILABLE;

这里写图片描述

可以用类型信息查询方法来检视类继承体系
isMemberOfClass:判断出对象是否为某个特定类的实例
isKindOfClass:判断出对象是否为某类或攀升累的实例

Teacher *teacher = [[Teacher alloc] init];[teacher isKindOfClass:[Teacher class]];//yes[teacher isKindOfClass:[NSObject class]];//yes[teacher isMemberOfClass:[Teacher class];//yes[teacher isMemberOfClass:[NSObject class]];//no

注:1、每个实例都有一个指向Class对象的指针,泳衣表明其类型,而这些Class对象则构成了类的继承体系
2、如果对象类型无法在编译期确定,那么久应该使用类型信息查询来探知
3、尽量食用类型信息查询方法来确定对象类型,而不要直接比较类对象,因为某些对象可能实现了消息转发功能

十、理解NSCopying协议
在使用对象时经常需要拷贝它,在oc中此操作通过copy方法完成,如果想令自己的类支持拷贝操作,那就要实现NSCopying协议,该协议有个方法:

-(id)copyWithZone:(NSZone *)zone;//以前在开发程序时,会据此把内存分成不同的“区”(zone),而创建对象会在某个区里面。现在不用了,每个程序只有一个区:“默认区”(default zone)。不必担心zone这个参数。//.h文件@interface YCFPerson : NSObject<NSCopying>@property (nonatomic, copy, readonly) NSString *firstName;@property (nonatomic, copy, readonly) NSString *lastName;- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName;@end//.m文件@implementation YCFPerson- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName{    if (self == [super init]) {        _firstName = firstName;        _lastName = lastName;    }    return self;}//在当前这个copyWithZone中,我们直接把拷贝的对象交给“指定的初始化方法initWithFirstName”初始化,然而有时候,除了拷贝对象,还要完成其他一些操作,比如类对象中的数据结构可能并未在初始化方法中设置好,需要另行设置。-(id)copyWithZone:(NSZone *)zone{    //此处一定要通过[self class]方法返回的对象调用allocWithZone:方法。因为指针可能实际指向的是YCFPerson的子类。[self class]就可以返回正确的类的类型对象了。    YCFPerson *copy = [[[self class] allocWithZone:zone] initWithFirstName:_firstName andLastName:_lastName];    return copy;}

NSCopying协议与NSMutableCopying的区别主要是在于,返回的对象是否是可变类型的。遵循NSMutableCopying协议,需要实现如下方法

- (id)mutableCopyWithZone:(NSZone *)zone;//.h文件@interface YCFSon : NSObject<NSMutableCopying>@property (nonatomic, copy, readonly) NSString *firstName;@property (nonatomic, copy, readonly) NSString *lastName;- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName;@end//.m文件@implementation YCFSon- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName{    if (self == [super init]) {        _firstName = firstName;        _lastName = lastName;    }    return self;}- (id)mutableCopyWithZone:(NSZone *)zone{     YCFSon *copy = [[[self class] allocWithZone:zone] initWithFirstName:_firstName andLastName:_lastName];    return copy;}@end

注意:1、若返回一个 不可变的拷贝,需要实现NSCopying,若返回一个可变的拷贝,需要实现NSMutableCopying协议。
2、需要注意是“深拷贝”还是“浅拷贝”。深拷贝就是在拷贝对象自身时,将其底层数据也一并复制过来。浅拷贝只拷贝容器对象本身,而不复制其中的数据。

0 0
原创粉丝点击