iOS-copy与mutableCopy浅析

在iOS开发中,当提到深拷贝和浅拷贝的时候,大家都说懂,简单;都会说,浅拷贝:指针(地址)拷贝,不会产生新对象;深拷贝:内容拷贝,会产生新对象
但当问及大家copy与mutableCopy的时候,他们各自是深拷贝还是浅拷贝的时候,谁又有底气答对呢?下面一起研究下吧


1、不可变字符串的拷贝

      NSString *string = @"string";

      NSString *str1 = [string copy];                // 没有产生新对象 【浅拷贝】
      NSMutableString *str2 = [string mutableCopy];  // 产生新对象    【深拷贝】

      NSLog(@"%p %p %p", string, [string copy], [string mutableCopy]); 

打印结果如下:
这里写图片描述
根据打印结果解析:
当不可变字符串调用copy的时候,指针地址没有发生改变,也就意味着没有产生新的对象,所以属于浅拷贝;
当不可变字符串调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。


2、可变字符串的拷贝

      NSMutableString *string = [NSMutableString string];
      [string appendString:@"text1"];

      NSString *str1 = [string copy];              // 产生新对象,变为不可变字符串【深拷贝】
      NSMutableString *str2 = [string mutableCopy];// 产生新对象,还是可变字符串  【深拷贝】

      [str2 appendString:@"text2"];

      NSLog(@"%p %p %p", string, [string copy], [string mutableCopy]);
      NSLog(@"%@ %@ %@", string, str1, str2);

打印结果如下:
这里写图片描述
根据打印结果解析:
当可变字符串调用copy的时候,指针地址发生了改变,也就意味着产生新的对象,所以属于深拷贝;
当可变字符串调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。


3、不可变数组的拷贝

      NSArray *array = @[@"text1", @"text2"];

      NSArray *array1 = [array copy];               // 没有产生新对象  【浅拷贝】

      NSMutableArray *array2 = [array mutableCopy]; // 产生新对象,变为可变数组【深拷贝】

      [array2 addObject:@"text3"];

      NSLog(@"%p %p %p", array, array1, array2);
      NSLog(@"%@ %@ %@", array, array1, array2);

打印结果如下:
这里写图片描述
根据打印结果解析:
当不可变数组调用copy的时候,指针地址没有发生改变,意味着没有产生新的对象,所以属于浅拷贝;
当不可变数组调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。


4、可变数组的拷贝

      NSMutableArray *mutableArray = @[@"text1", @"text2"].mutableCopy;

      NSArray *array1 = [mutableArray copy];                      // 产生新对象,变为不可变数组【深拷贝】

      NSMutableArray *mutableArray1 = [mutableArray mutableCopy]; // 产生新对象,变为可变数组  【深拷贝】

      [mutableArray1 addObject:@"text3"];

      NSLog(@"%p %p %p", mutableArray, [mutableArray copy], [mutableArray mutableCopy]);
      NSLog(@"%@ %@ %@", mutableArray, array1, mutableArray1);

打印结果如下:
这里写图片描述
根据打印结果解析:
当可变数组调用copy的时候,指针地址发生了改变,也就意味着产生新的对象,所以属于深拷贝;
当可变数组调用mutableCopy的时候,指针地址发生了改变,意味着产生新的对象,所以属于深拷贝。


5、自定义对象的拷贝

由于自定义对象不考虑可变,所以忽略mutableCopy

首先,当对象需要调用 copy 的时候,需要遵守遵守 NSCopying 协议 和 调用 copyWithZone:这个方法

@interface Dog : NSObject
/** 姓名 */
@property (nonatomic, copy) NSString *name;
/** 年龄 */
@property (nonatomic, assign) int age;

@end


// 需要遵守 NSCopying 协议
@interface Dog () <NSCopying>

@end

@implementation Dog
// 当对象需要调用 copy 的时候,需要调用 copyWithZone:这个方法
- (id)copyWithZone:(NSZone *)zone
{
    Dog *dog = [[Dog allocWithZone:zone] init];
    dog.name = self.name;
    dog.age  = self.age;
    return dog;
}
@end
      Dog *dog = [[Dog alloc] init]; // [object copyWithZone:zone]
      dog.name = @"huahua";
      dog.age  = 1;

      Dog *newDog = [dog copy]; // 产生新对象【深拷贝】
      NSLog(@"%@ %@",dog,newDog);
      NSLog(@"%@ %@",dog.name,newDog.name);

打印结果如下:
这里写图片描述
根据打印结果解析:
当自定义对象调用copy的时候,指针地址发生了改变,也就意味着产生新的对象,所以属于深拷贝;


6、属性中的copy 和 strong

在平时定义属性的时候,对于NSString 和 block 我们经常用 copy 来修饰
数组和字典等类型用 strong 来修饰;

当使用 copy 修饰属性的时候,属性的setter方法会调用[object copy]产生新的对象,
这样,当原object对象的值发生改变时,并不影响新对象值;

// 定义NSString
 @property(nonatomic, copy) NSString *name;
 .
 .
 .
// 当调用上面的copy的时候,等价于下面的代码
- (void)setName:(NSString *)name {
      if (_name != name) {
         [_name release];
          _name = [name copy];
       }
}

当使用 strong 修饰属性的时候,属性的setter方法会直接强引用该对象,
这样,当原object对象的值发生改变时,新对象的属性也改变;
例如:我们平时使用strong修饰的NSMutableArray,这个可变数组在当前文件中只有一个,而且是可变的;

/** 数组 */
@property(nonatomic,strong)NSMutableArray *array;
.
.
.
// 当调用上面的strong的时候,等价于下面的代码
-(void)setArray:(NSMutableArray *)array{
    _array = array;
}
以前面的自定义Dog对象进行举例:
    // 定义一个可变的字符,作为小狗的name
    NSMutableString *dogName = [NSMutableString stringWithString:@"huahua"];   // dogName == "huahua"

    Dog *dog = [[Dog alloc] init];
    // 将字符赋值给dog的name属性
    dog.name = dogName;
    // 当小狗的name值发生改变时
    [dogName appendString:@"lvlv"];   // dogName == "huahualvlv"
    // 小狗的名还是原来的姓名
    NSLog(@"%@",dog.name);            // 打印结果:huahua

分析:当给dog.name 赋值时,会将 [dogName copy] 后的结果赋值给 dog.name,这样,当dogName字符的值发生改变后,不会影响 dog.name 的值;


总结:当不可变类型对象调用copy拷贝后,不会产生新的对象,属于浅拷贝,其他类型对象不管调用copy亦或是mutableCopy,都会产生新的对象,属于深拷贝!
这里写图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的 iOS 通讯录修改备注的代码实现示例: ```obj-c // 获取联系人信息并修改备注 - (void)updateContactRemarkWithName:(NSString *)name remark:(NSString *)remark { // 创建联系人名称搜索谓词 NSPredicate *predicate = [CNContact predicateForContactsMatchingName:name]; // 创建联系人信息请求对象 NSArray *keysToFetch = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactMiddleNameKey, CNContactNicknameKey, CNContactPhoneNumbersKey, CNContactIdentifierKey]; CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; fetchRequest.predicate = predicate; NSError *error; CNContactStore *store = [[CNContactStore alloc] init]; // 遍历符合条件的联系人 [store enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { // 创建可变联系人对象 CNMutableContact *mutableContact = [contact mutableCopy]; // 设置备注信息 mutableContact.note = remark; // 保存修改后的联系人信息 CNSaveRequest *request = [[CNSaveRequest alloc] init]; [request updateContact:mutableContact]; [store executeSaveRequest:request error:nil]; }]; } // 更新好友备注信息 - (void)updateFriendRemarkWithContact:(CNContact *)contact { // 获取好友列表中的好友信息 NSString *friendId = [self getFriendIdByContactId:contact.identifier]; if (friendId) { // 调用即时通讯 SDK 的接口更新好友备注信息 [self updateFriendRemarkWithFriendId:friendId remark:contact.note]; } } ``` 在这个示例中,我们首先根据姓名搜索联系人信息,然后遍历符合条件的联系人,创建可变联系人对象,并设置备注信息。最后通过 CNSaveRequest 和 CNContactStore 的 executeSaveRequest 方法保存修改后的联系人信息。 在更新好友备注信息时,我们需要根据联系人的唯一标识符获取到好友的唯一标识符,然后调用第三方即时通讯 SDK 的接口更新好友备注信息。 需要注意的是,这个示例中的代码只是一个简单的实现,具体实现方式需要根据具体的业务需求进行调整。同时,在实现中还需要考虑到错误处理和用户授权等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值