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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值