• 浅析Objective-C的copy


    一直对NSObject的copy方法似懂非懂,今天工作做完了,整理一下

    深复制和浅复制是什么在这里就不赘述

    今天主要分三种类型对copy进行探讨:系统非容器类对象、系统容器类对象和自定义对象

    系统非容器类对象(NSString,NSNumber等)

    NSString *str1 = @"123";
    NSString *str2 = [str1 copy];
    NSString *str3 = [str1 mutableCopy];
    NSMutableString *str4 = [str1 copy];
    NSMutableString *str5 = [str1 mutableCopy];
    //    [str3 appendString:@"456"];   //编译出错
    //    [str4 appendString:@"456"];   //运行出错

    如上代码,打印结果如下图

    结论:

    1.对比所有string的地址,发现copy返回的是浅复制(只复制了指针),mutableCopy返回的是深复制(重新分配了内存)

    2.str3在编译时为NSString,运行时为NSMutableString类型,从图中str3的类型为__NSCFString可证明,所以修改操作在编译的时候就会报错

    3.str4在编译时为NSMutableString,运行时为NSString类型,从图中str4的类型为__NSCFConstantString可证明。所以对str4进行append等修改,编译可通过,但运行时会直接crash

    系统容器类对象(NSArray,NSDictionary等)

    NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"], @"2", nil];
    NSArray *array2 = [array1 copy];
    NSArray *array3 = [array1 mutableCopy];
    NSMutableArray *array4 = [array1 copy];
    NSMutableArray *array5 = [array1 mutableCopy];

    结论:

    array1-array5的原理同NSString部分,但是注意mutableCopy返回的深复制,是对容器的深复制,容器里的元素仍然是浅复制

    疑问:那如何对容器内的元素也进行深复制呢?

    第一种方法:使用initWithArray:copyItems:方法

    NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"], @"2", nil];
    NSArray *array6 = [[NSArray alloc] initWithArray:array1 copyItems:YES];

    此时array6的第一个元素是array1的第一个元素的深复制,但是第二个元素则是浅复制。

    莫非用官方的api也会出错?其实不是的,因为对于不可变对象,对其进行浅复制就足够,因为你改变不了其值!

    所以initWithArray:copyItems:可以实现一种不够彻底的深复制

    疑问:如果真的需要对容器中的不可变对象进行深复制,那怎么办?

    第二种方法:使用NSKeyedUnarchiver

    NSArray *array7 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1]];

    NSKeyedUnarchiver是真正意义上的深复制

    自定义对象

     以上,NSString和NSArray都是默认实现了NSCopying和NSMutableCopying协议,才能响应copy和mutableCopy方法

    如果是自定义对象,那么怎么让其响应copy和mutableCopy方法呢?

    上代码

    //
    //  MyObj.h
    //  No
    //
    //  Created by Norcy on 16/1/28.
    //  Copyright © 2016年 Norcy. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface MyObj : NSObject<NSCopying, NSMutableCopying>
    @property (nonatomic, retain) NSMutableString *str1;
    @property (nonatomic, retain) NSString *str2;
    @property (nonatomic, assign) int num;
    @end
    MyObj.h

      

    //
    //  MyObj.m
    //  No
    //
    //  Created by Norcy on 16/1/28.
    //  Copyright © 2016年 Norcy. All rights reserved.
    //
    
    #import "MyObj.h"
    
    @implementation MyObj
    - (id)init
    {
        if (self = [super init])
        {
            self.str1 = [[NSMutableString alloc] init];
            self.str2 = [[NSString alloc] init];
            self.num = -1;
        }
        return self;
    }
    
    - (id)copyWithZone:(NSZone *)zone
    {
        MyObj *obj = [[[self class] allocWithZone:zone] init];
        obj.str1 = [self.str1 copyWithZone:zone];
        obj.str2 = [self.str2 copyWithZone:zone];
    //    obj.str1 = [self.str1 copy];  //这样写也可以
    //    obj.str2 = [self.str2 copy];
        obj.num = self.num;
        return obj;
    }
    
    - (id)mutableCopyWithZone:(NSZone *)zone
    {
        MyObj *obj = [[[self class] allocWithZone:zone] init];
        obj.str1 = [self.str1 mutableCopyWithZone:zone];
        obj.str2 = [self.str2 mutableCopyWithZone:zone];
    //    obj.str1 = [self.str1 mutableCopy];   //这样写也可以
    //    obj.str2 = [self.str2 mutableCopy];
        obj.num = self.num;
        return obj;
    }
    @end
    MyObj.m

    调用方法如下:

    MyObj *obj = [[MyObj alloc] init];
    obj.str1 = @"123";
    obj.str2 = @"345";
    obj.num = 1;
    MyObj *obj2 = [obj copy];
    MyObj *obj3 = [obj mutableCopy];

    如上代码,打印结果如下图


    可以看到

    (1)copy方法准确返回了一个新的对象,且对象的属性是浅复制

    (2)mutableCopy方法准确返回了一个新的对象,且对象的属性是深复制

    (3)想要实现copy方法,需要让对象声明遵循<NSCopying>和<NSMutableCopying>协议,并且实现实现copyWithZone:和mutableCopyWithZone:方法

     (注意哦,不是实现copy和mutableCopy方法;还有zone参数是什么鬼?其实zone参数的存在是历史原因,现在我们不必太过关心它)

    (4)以下这2种写法在该情况下是等价的

        obj.str1 = [self.str1 copyWithZone:zone];
        obj.str2 = [self.str2 copyWithZone:zone];
    // obj.str1 = [self.str1 copy]; //这样写也可以 // obj.str2 = [self.str2 copy];

    参考文章:

    《浅谈copy和retain》

  • 相关阅读:
    射极跟随器的设计及参数确定
    三极管放大电路 之共射放大电路参数确定
    allegro生成光绘文件时,通过cam打开,*.drl钻孔文件不识别,为Unknow类型
    allegro 16.6 空心焊盘的制作
    cadence16.6 如何对齐元件
    Allegro中板子边框不封闭导致的z-copy无法用的问题
    Android Thermal-engine
    《万历十五年》--黄仁宇
    USB 接口探测分类
    Android电池电量跳变
  • 原文地址:https://www.cnblogs.com/chenyg32/p/5167194.html
Copyright © 2020-2023  润新知