【OC梳理】Copy、KVC、KVO

Copy

OC中copy的作用是:利用一个源对象产生一个副本对象,它们之间不会相互影响。

关于深拷贝与浅拷贝

深拷贝是指对对象的具体内容进行复制,并占用新的内存空间,浅拷贝就是对内存地址的复制。
自定义的类如果要深拷贝,需要遵循 NSCopying, NSMutableCopying 协议,在协议方法中实现copy相关方法。
数组的深拷贝,也需要自己将所有对象拷贝一份再添加。
下面的代码:

    NSMutableArray *array = [NSMutableArray array];
    [array addObject:[NSObject new]];
    [array addObject:[NSObject new]];
    [array addObject:[NSObject new]];
    [array addObject:[NSObject new]];
    NSArray *copyArray = [array copy];
    NSArray *copycopyArray = [copyArray copy];
    NSMutableArray *mutACopy = [array mutableCopy];
    NSMutableArray *arrCopy = [copyArray mutableCopy];
    NSLog(@"原来的数组            :%p ----> %p",&array,*&array);
    NSLog(@"copy的数组           :%p ----> %p",&copyArray,*&copyArray);
    NSLog(@"copycopy的数组       :%p ----> %p",&copycopyArray,*&copycopyArray);
    NSLog(@"mutableCopy原来的数组 :%p ----> %p",&mutACopy,*&mutACopy);
    NSLog(@"mutableCopy copy的数组:%p ----> %p",&arrCopy,*&arrCopy);

输出的结果如下:

... Demo[11327:4606426] 原来的数组            :0x7ffee226d9a0 ----> 0x60400044a9e0
... Demo[11327:4606426] copy的数组           :0x7ffee226d998 ----> 0x60400044aa10
... Demo[11327:4606426] copycopy的数组       :0x7ffee226d990 ----> 0x60400044aa10
... Demo[11327:4606426] mutableCopy原来的数组 :0x7ffee226d988 ----> 0x60400044fcc0
... Demo[11327:4606426] mutableCopy copy的数组:0x7ffee226d980 ----> 0x60400044fcf0

打断点可以看到所有的Array中的元素的地址都是相同的,并没有进行复制,并从输出结果看出:

copy的对象为MutableArray时,会有一个新的指针指向新的内存地址(新的Array对象)。
copy的对象为Array时,会有一个新的指针指向原来的内存地址(原来的Array对象)。
mutableCopy的对象为MutableArray时,会有一个新的指针指向新的内存地址(新的MutableArray对象)。
mutableCopy的对象为Array时,会有一个新的指针指向新的内存地址(新的MutableArray对象)。

参考文章:
Objective-C中的浅拷贝和深拷贝
OC数组中的深拷贝

KVC

KVC(Key Valued Coding),键值编码,即常说的反射机制,是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,进行属性的动态读写。
对于某些private属性,如果使用KVC进行修改,这就破坏了类的封装性(当然了有些情况不得不使用KVC进行修改)。

  • KVC的主要用途是ORM映射,就是dictionary与model的互转。

常用方法

//获取值的方法
valueForKey:            //传入NSString属性的名字。
valueForKeyPath:        //传入NSString属性的路径,xx.xx形式。
valueForUndefinedKey    //它的默认实现是抛出异常,可以重写这个函数做错误处理。

修改值的方法
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:

使用KVC实现ORM

假定有一个商品model,其定义属性如下:

@property (nonatomic,copy) NSString * goodsId;      //商品ID
@property (nonatomic,copy) NSString * coverImage;   //封面
@property (nonatomic,copy) NSString * shopPrice;    //商城价(零售价)
@property (nonatomic,copy) NSString * sales;        //销量
//...

服务器返回的字符串为:

{
  "goods_id":"7",
  "cover_image":"http://www.nenyimall.com/products/H6200IFLO.jpg",
  "shop_price":"¥15.00",
  "sales":"139",
  ...
}

其中有3个字段的key与我们定义的属性名有区别,这时候,只需重写下面两个方法:

-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    if ([key isEqualToString:@"goods_id"]) {
        [self setValue:value forKey:@"goodsId"];
    }else
    if ([key isEqualToString:@"cover_image"]) {
        [self setValue:value forKey:@"coverImage"];
    }else
    if ([key isEqualToString:@"shop_price"]) {
        [self setValue:value forKey:@"shopPrice"];
    }
}

-(id)valueForUndefinedKey:(NSString *)key{
    id result = nil;
    if ([key isEqualToString:@"goods_id"]) {
        result = [self valueForKey:@"goodsId"];
    }else
    if ([key isEqualToString:@"cover_image"]) {
        result = [self valueForKey:@"coverImage"];
    }else
    if ([key isEqualToString:@"shop_price"]) {
        result = [self valueForKey:@"shopPrice"];
    }
    return result;
}

然后就可以使用setValuesForKeysWithDictionary:将dictionary转换为model;
使用dictionaryWithValuesForKeys:将属性转换为dictionary。
参考文章:
iOS开发-OC篇-KVC详解

KVO

KVO(Key Valued Observer),键值观察,是使用获取其他对象的特定属性变化的通知机制。所有NSObject的子类都支持这个机制。

常用语法

/**
 创建一个观察者
 @param observer 观察者
 @param keyPath 被观察的属性
 @param options 传递给接收者的值的类型 NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
 @param context 上下文,可用于区分注册者
 */
[被观察对象 addObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(nullable void *)#>];

/**
 观察者的回调方法
 @param keyPath 被观察的属性
 @param object 被观察的属性值
 @param change 变化的记录
 @param context 上下文
 */
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
  //do something
}

/**
 移除观察者
 @param observer 观察者
 @param keyPath 被观察的属性
 */
[被观察对象 removeObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#>];

局限性

父类和子类同时存在KVO时(监听同一个对象的同一个属性),很容易出现对同一个keyPath进行两次removeObserver操作,从而导致程序crash。要避免这个问题,就需要区分出KVO是self注册的,还是superClass注册的,我们可以在 -addObserver:forKeyPath:options:context:和-removeObserver:forKeyPath:context这两个方法中传入不同的context进行区分。

参考文章:
OC中KVO的基本概念和使用方法
iOS开发-KVO的奥秘
iOS下KVO使用过程中的陷阱

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • 转自 iOS 面试常见问题最全梳理 序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了。今年,找...
    ZMJun阅读 787评论 0 11
  • OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性...
    失忆的程序员阅读 473评论 0 1
  • 序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了。今年,找过工作人可能会更深刻地体会到今年的就...
    Jack_lin阅读 78,279评论 110 1,945
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,113评论 29 470
  • OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性...
    克鲁德李阅读 444评论 0 0