iOS - 如何深拷贝Array内元素、自定义对象、及自定义对象的属性(上)

简介: 关于深拷贝、浅拷贝,请看上篇iOS - 深拷贝、浅拷贝探索验证
  1. 上篇我们知道:


  • copy: 对NSArray是浅拷贝,NSMutableArray是深拷贝


  • mutableCopy: 始终是深拷贝


  • 无论深浅拷贝,集合对象内元素都是浅拷贝


  1. 本篇主要探索


  • 实现NSArray内元素的拷贝


通过本文你将知道


  • 深拷贝NSArray


  • 深拷贝NSArray内元素Person


  • 深拷贝NSArray内元素Person的属性nickname


本文代码较多,建议一步步耐心跟着代码排查,会有不少收货


探索过程


1. 系统Api


我们发现系统系统了方法- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag

其中copyItems:(BOOL)flag表示是否拷贝元素,我们先代码测试一下

NSString *str1 = @"hello world";
    NSMutableString *str2 = [NSMutableString stringWithString:@"hello world"];
    NSArray *array1 = [NSArray arrayWithObjects: str1, str2, nil];
    NSMutableArray *array2 = [[NSMutableArray alloc] initWithArray:array1 copyItems:true];
    NSLog(@"\n array1 = %p class = %@ \n", array1, [array1 class]);
    NSLog(@"\n array2 = %p class = %@ \n", array2, [array2 class]);
    NSLog(@"\n\n======== 元素是String ======== ");
    NSLog(@"\n obj0 = %p class = %@ \n", array1[0], [array1[0] class]);
    NSLog(@"\n obj0 = %p class = %@ \n", array2[0], [array2[0] class]);
    NSLog(@"\n\n======== 元素是mutableString ========");
    NSLog(@"\n obj0 = %p class = %@ \n", array1[1], [array1[1] class]);
    NSLog(@"\n obj0 = %p class = %@ \n", array2[1], [array2[1] class]);


查看输出(为了下文对比,我对输出做了line标记)

2021-05-09 10:59:16.343163+0800 AlgorithmDemo[9904:51756] 
 array1 = 0x100607650 class = __NSArrayI  (line1)
 array2 = 0x1006074a0 class = __NSArrayM (line2)
======== 元素是String ======== 
 obj0 = 0x100008220 class = __NSCFConstantString (line3)
 obj0 = 0x100008220 class = __NSCFConstantString (line4)
======== 元素是mutableString ========
 obj0 = 0x100606330 class = __NSCFString (line5)
 obj0 = 0x100605430 class = __NSCFString (line6)


根据输出我们对得出系统initWithArray : copyItems :方法如下结论


  • 该方法对NSArray对象是深拷贝 (严格意义来说此处不能称为拷贝,是生成新对象) (line1 line2)


  • 当数组内元素为不可变对象时,该方法对元素执行浅拷贝(line3 line4)


  • 当数组内元素为可变对象时,该方法对元素执行深拷贝(line4 line5)


由此我们知道,当我们想深拷贝NSArray及其内部的元素时,用系统方法- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag是不行的


2. 归档


如果我们对Array执行归档再解档,结果会是什么样的呢,我们代码测试一下

NSString *str1 = @"hello world";
    NSMutableString *str2 = [NSMutableString stringWithString:@"hello world"];
    NSArray *array1 = [NSArray arrayWithObjects: str1, str2, nil];
    NSMutableArray *array2 = [[NSMutableArray alloc] initWithArray:array1 copyItems:true];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array1];
    NSMutableArray *array3 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSLog(@"\n array1 = %p class = %@ \n", array1, [array1 class]);
    NSLog(@"\n array2 = %p class = %@ \n", array2, [array2 class]);
    NSLog(@"\n array3 = %p class = %@ \n", array3, [array3 class]);
    NSLog(@"\n\n======== 元素是String ======== ");
    NSLog(@"\n obj0 = %p class = %@ \n", array1[0], [array1[0] class]);
    NSLog(@"\n obj0 = %p class = %@ \n", array2[0], [array2[0] class]);
    NSLog(@"\n obj0 = %p class = %@ \n", array3[0], [array3[0] class]);
    NSLog(@"\n\n======== 元素是mutableString ========");
    NSLog(@"\n obj0 = %p class = %@ \n", array1[1], [array1[1] class]);
    NSLog(@"\n obj0 = %p class = %@ \n", array2[1], [array2[1] class]);
    NSLog(@"\n obj0 = %p class = %@ \n", array3[1], [array3[1] class]);


查看输出

2021-05-09 11:14:50.710409+0800 AlgorithmDemo[12261:67019] 
 array1 = 0x1006b9e40 class = __NSArrayI  (line1)
 array2 = 0x1006ba180 class = __NSArrayM  (line1)
 array3 = 0x1006b7410 class = __NSArrayI  (line1)
======== 元素是String ======== 
 obj0 = 0x100008220 class = __NSCFConstantString  (line1)
 obj0 = 0x100008220 class = __NSCFConstantString  (line1)
 obj0 = 0x1006b6d20 class = __NSCFString  (line1)
======== 元素是mutableString ========
 obj0 = 0x1006b9cb0 class = __NSCFString  (line1)
 obj0 = 0x1006ba0e0 class = __NSCFString  (line1)
 obj0 = 0x1006b70e0 class = __NSCFString  (line1)


根据输出,我们很明显得出如下结论


  • 对Array归档并解档后,会生成新的Array对象


  • Array对象内的不可变元素进行了深拷贝


  • Array对象内的可变元素进行了深拷贝


由此,我们得出对如下总结


  • 只深拷贝NSArray对象,我们用mutableCopy就可以


  • 只深拷贝NSMutableArray对象,我们用Copy或mutableCopy都可以


  • 深拷贝Array对象及内部元素,我们可以通过归档的方法解决


3. 重写copyWithZonemutableCopyWithZone的方式深拷贝自定义对象


我们写一个person类测试一下

//
//  Person.h
//  AlgorithmDemo
//
//  Created by Ternence on 2021/5/9.
//
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *nickname;
@end


测试代码如下

Person *person = [[Person alloc] init];
    person.nickname = @"码代码的小马";
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:person, nil];
    NSArray *array2 = [array1 copy];
    NSMutableArray *array3 = [array1 mutableCopy];
    NSLog(@"\n array1 = %p class = %@", array1, [array1 class]);
    NSLog(@"\n array2 = %p class = %@", array2, [array2 class]);
    NSLog(@"\n array3 = %p class = %@", array3, [array3 class]);
    NSLog(@"\n\n======== 数组内元素 ======== ");
    NSLog(@"\n array1[0] = %p class = %@", array1[0], [array1[0] class]);
    NSLog(@"\n array2[0] = %p class = %@", array2[0], [array2[0] class]);
    NSLog(@"\n array3[0] = %p class = %@", array3[0], [array3[0] class]);


相关文章
|
JavaScript 前端开发 API
【JavaScript】<JS内建对象>JavaScript内建对象-Array对象
【1月更文挑战第17天】【JavaScript】<JS内建对象>JavaScript内建对象-Array对象
|
iOS开发 UED
实现一个自定义的iOS动画效果
【4月更文挑战第9天】本文将详细介绍如何在iOS平台上实现一个自定义的动画效果。我们将通过使用Core Animation框架来实现这个动画效果,并展示如何在不同的场景中使用它。文章的目标是帮助读者理解如何使用Core Animation框架来创建自定义动画,并提供一个简单的示例代码。
222 1
|
8月前
|
移动开发 运维 供应链
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
供应链 JavaScript 前端开发
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
Web App开发 存储 前端开发
别再用双层遍历循环来做新旧数组对比,寻找新增元素了!使用array.includes和Set来提升代码可读性
这类问题的重点在于能不能突破基础思路,突破基础思路是从程序员入门变成中级甚至高级的第一步,如果所有需求都通过最基础的业务逻辑来做,是得不到成长的。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
253 1
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
216 5
|
Swift iOS开发 UED
实现一个自定义的iOS动画效果
本文介绍如何使用Swift和UIKit在iOS应用中实现一个自定义按钮动画,当按钮被点击时,其颜色从蓝色渐变为绿色,形状从圆形变为椭圆形,释放后恢复原状。通过UIView动画方法实现这一效果,代码示例展示了动画的平滑过渡和状态切换,有助于提升应用的视觉体验和用户交互。
282 1
|
存储 JavaScript 前端开发
JavaScript Array(数组) 对象
JavaScript Array(数组) 对象
116 3
|
iOS开发 UED 开发者
iOS 手势中cancelsTouchesInView delaysTouchesBegan delaysTouchesEnded 三种属性的使用
iOS 手势中cancelsTouchesInView delaysTouchesBegan delaysTouchesEnded 三种属性的使用
480 10

热门文章

最新文章

  • 1
    PHP 数组查找:为什么 `isset()` 比 `in_array()` 快得多?
    139
  • 2
    Java 中数组Array和列表List的转换
    572
  • 3
    JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
    548
  • 4
    通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式、聚合统计、处理树结构数据和性能优化,reduce()的使用详解(附实际应用代码)
    1306
  • 5
    通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
    375
  • 6
    通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
    241
  • 7
    多维数组操作,不要再用遍历循环foreach了!来试试数组展平的小妙招!array.flat()用法与array.flatMap() 用法及二者差异详解
    149
  • 8
    别再用双层遍历循环来做新旧数组对比,寻找新增元素了!使用array.includes和Set来提升代码可读性
    175
  • 9
    Array.forEach实战详解:简化循环与增强代码可读性;Array.forEach怎么用;面对大量数据时怎么提高Array.forEach的性能
    125
  • 10
    深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解
    429
  • 下一篇
    oss云网关配置