oc——拷贝

透心凉mmm 透心凉mmm     2022-08-28     736

关键词:

一、什么是拷贝

在 OC 中,可以使用两个方法分别对一个 OC 对象进行拷贝(产生副本),产生的副本和原对象具有相同的内容,这两个方法分别是

- (id)copy;
- (id)mutableCopy;

如果想使用 copy 方法,那么该类必须遵守 <NSCopying> 协议

如果想使用 mutableCopy 方法,那么该类必须遵守 <NSMutableCopying> 协议

 

在看它们的区别之前,我们先来解释一下拷贝的分类

 

拷贝的分类 

  1)浅拷贝 : 即指针拷贝,简单的说就是拷贝指针,不会产生新的对象,原对象的 引用计数 +1

  2)深拷贝 : 会产生一个新的对象,原对象的引用计数不变,新对象的引用计数为 1

 

注意 : 只有不可变对象(NSString、NSArray、NSDictionary等)调用 copy 方法才是浅拷贝,其余都是深拷贝

 

copy 和 mutableCopy 方法的区别

  1)copy : 创建的是一个不可变对象(NSString、NSArray、NSDictionary)

  2)mutableCopy : 创建的是一个可变的对象 (NSMutableString、NSMutableArray、NSMutableDictionary)

 

二、拷贝示例

 

1)不可变对象调用 copy

 1 void test_2() {
 2 
 3     // 引用计数 : 1
 4     NSString * str_1 = [[NSString alloc] initWithFormat:@"age is %i", 10];
 5     
 6     // copy 语法并没有产生一个新的对象,而是指向原来的对象
 7     // 引用计数 : 2
 8     NSString * str_2 = [str_1 copy];
 9     
10     NSLog(@"str_1 --- %p", str_1);
11     NSLog(@"str_2 --- %p", str_2);
12     
13     [str_1 release];
14     
15     [str_1 release];
16     
17 
18 }

 

运行结果

总结 : 可见,不可变对象调用 copy 方法不会产生新的对象,如图

 

2)可变对象调用 copy

 1 void test_3() {
 2 
 3     NSMutableString * mulString = [NSMutableString stringWithFormat:@"age is %i", 10];
 4     
 5     // 可变对象调用 copy 是深拷贝
 6     NSString * str = [mulString copy];
 7     
 8     NSLog(@"mulString --- %p", mulString);
 9     NSLog(@"str --- %p", str);
10 
11     [mulString release];
12     
13     [str release];
14 
15 }

运行结果

总结 : 可变对象调用 copy 是深拷贝,会产生新的对象,如图

 

3)不可变对象调用 mutableCopy

 1 void test_1() {
 2 
 3     // 引用计数 : 1
 4     NSString * str = [[NSString alloc] initWithFormat:@"age is %i", 10];
 5     
 6     // 产生一个新的对象
 7     // 引用计数 : 1
 8     NSMutableString * mulStr = [str mutableCopy];
 9     
10     NSLog(@"str --- %p", str);
11     NSLog(@"mulStr - %p", mulStr);
12     
13     [str release];
14     
15     [mulStr release];
16 
17 }

运行结果

总结 : 不可变对象调用 mutableCopy 会产生一个新的对象,如图

 

4)可变对象调用 mutableCopy

 

 1 void test_4 () {
 2 
 3     // 引用计数 1
 4     NSMutableString * mulString = [[NSMutableString alloc] initWithFormat:@"age is %i", 10];
 5     
 6     // 可变对象调用 mutableCopy 产生新的对象
 7     // 引用计数 1
 8     NSMutableString * mulString_2 = [mulString mutableCopy];
 9     
10     NSLog(@"mulString --- %p", mulString);
11     NSLog(@"mulString_2 --- %p", mulString_2);
12     
13     [mulString release];
14     
15     [mulString_2 release];
16 
17 }

 

运行结果

总结 : 可变对象调用 mutableCopy 会产生一个新的对象,如图

 

 三、自定义类对象

先定义一个 Student 类,如下

// Student.h
@interface Student : NSObject

// copy 代表 setter 方法 release 旧对象,copy 新对象
@property (nonatomic, copy) NSString * name;

@end

// Student.m
#import "Student.h"

@implementation Student

- (void)dealloc {
    
    NSLog(@"%@ 被释放", _name);

    [_name release];
    
    [super dealloc];

}

@end

其中,name 属性选择 copy 语法,选择 copy 时其自动生成的 setter 方法等价于下面

 1 - (void)setName:(NSString *)name {
 2 
 3     if(_name != name) {
 4     
 5         [_name release];
 6         
 7         _name = [name copy];
 8         
 9     }
10 
11 }

在 main 中编写如下代码

 1 void test_5() {
 2 
 3     Student * stu = [[Student alloc] init];
 4     
 5     NSMutableString * string = [NSMutableString stringWithFormat:@"age is %i", 10];
 6     
 7     stu.name = string;
 8     
 9     // 此时,改变外部的 string 并不会影响到 stu 内部的  string
10     
11     [string appendString:@"ab"];
12     
13     NSLog(@"string: %@", string);
14     NSLog(@"stu.name: %@", stu.name);
15     
16     [stu release];
17 
18 }

运行结果 

分析 : main 函数中执行到第 5 行代码的内存图如下

 

注意,此时 stu 中的 name 实例变量还未指向任任何对象,所以是 nil

点在第 6 行,运行此行时,会调用 setName: 方法,并将 string 作为 setName: 的参数

  1)首先判断 stu 的当前 name 实例变量和传入参数的 是否是同一个,显然不是

  2)然后将 stu 的 name 实例变量 指向的对象释放,此时 nil,nil 执行 release 是可以的;如果不是 nil,则当前 name 实例变量指向的对象则会被释放

  3)然后会对传入的参数 name(就是 main 中的 string)调用 copy 方法,这里注意一下,因为我在定义 name 属性的时候,使用的类型是 NSString(不可变),所以 setName: 参数的类型也就是 NSString,但是,在 main 中的 string 是 NSMutableString 类型,因为 NSMutableString 是 NSStirng 的子类,所以是可以传给 setName: 中的形参的;其实,string 和 name 所指的对象都是同一个,且它的类型就是 NSMutableString;所以,对一个 可变对象调用 copy 方法,会产生一个新的对象,然后将这个新的对象的地址赋给 stu 的 name 实例变量,如图

此时,string 和 stu.name 所指的对象是不同的对象,修改 string 不会影响到 stu.name 的,所以结果就如上面那样了

 

四、NSCopying 和 NSMutableCopying 协议

若想让一个类的对象支持拷贝,就必须要将该类遵守 NSCopying 或 NSMutableCopying 协议

 

NSCopying 和 NSMutableCopying 协议中都只有一个方法,分别是

 

// NSCopying 协议的方法
- (id)copyWithZone:(nullable NSZone *)zone;

// NSMutableCopying 协议的方法
- (id)mutableCopyWithZone:(nullable NSZone *)zone;

 

 

当一个对象调用 copy 方法时, copy 方法就会自动去调用 copyWithZone: 方法来实现目的

copyWithZone: 方法的实现可以理解为下面的代码

 

 

首先声明一个 Person 类,并声明两个属性 name 和 age,且让 Person 遵循 NSCopying 协议

1 @interface Person : NSObject <NSCopying>
2 
3 @property (nonatomic, copy) NSMutableString * name;
4 
5 @property (nonatomic, assign) int age;
6 
7 @end

 

在 Person.m 文件中实现 copyWithZone: 方法,如下

 1 - (id)copyWithZone:(NSZone *)zone {
 2 
 3     // zone 是系统已经分配好为当前对象分配的内存
 4     // 不需要释放,要在外部释放
 5     
 6     Person * person = [[[self class] allocWithZone:zone] init];
 7     
 8     person.name = _name;
 9     person.age = _age;
10     
11     return person;
12 
13 }

总结 :

  1)在该方法中,一定要用 [self class] 来获取当前类,如果 Person 有个子类 Student,那么 Student 对象就会获得当前正确的类,而不是其父类 Person

  2)然后通过 allocWithZone: 方法创建一个指定好的内存空间进行分配,指定的内存空间由参数确定

  3)然后将当前对象的内容赋给新创建的对象

  4)最后返回这个对象,注意,一定要返回的是不可变对象

 

mutableCopyWithZone: 方法和 copyWithZone: 方法一样,只不过返回的是一个可变对象

 

详谈oc(object-c)深浅复制/拷贝-什么情况下用retain和copy

转载:http://www.cnblogs.com/langtianya/p/3722129.html读前小提示:对于深浅复制有一个清楚的了解,对于学习oc的朋友来说,至关重要。那么首先,我们要明白深浅复制是如何定义的呢。这里为了便于朋友们理解,定义如下。  浅... 查看详情

oc49--@class

...import"Car.h"//由于import是一个预编译指令,他会将""中的文件拷贝到import所在的位置。//并且import有一个特点,只要""中的文件发生了变化,那么import就会重新拷贝一次(更新操作)。//@class仅仅是告诉编译器,@class后面的名称是一 查看详情

oc知识点碎片(代码片段)

...clude完全一样。第二个用途:可以自动防止文件内容被重复拷贝,也就是说多次书写#import<Foundation/NSObjCRuntim.h>就只拷贝一次,相当于只写了一次。OC与C语言完全兼容,其入口也为main函数,定义方法与C语言完全一样。ObjectC的... 查看详情

iosjs交互之利用系统jscontext实现js调用oc方法

...js,css,需要注意的是当你向工程中拖入这些文件时,选择拷贝到工程中,(拖入的文件夹是蓝色的,相对路径),不然css,js的路径会存在问题 加载本地html: oc调用js:一句代码搞定  2.js调用oc  js调 查看详情

oc类的结构分析

...ass_rw_t是运行时生成的在类的加载过程中class_rw_t初始化并拷贝了class_ro_t中方法列表、属性列表、协议列表等同时把class_ro_t也保存自己里边注意这里并没有将成员变量列表(ivar_list_t)拷贝过去那么为什么要用到这个class_rw_t呢这里... 查看详情

[unity设计模式与游戏开发]原型模式(代码片段)

...,是我们生物工程史上的一次重大突破。克隆又称作拷贝,记得在做iOS开发的时候,刚接触OC开发谈的比较多一个知识点就是深拷贝和浅拷贝,浅拷贝只是拷贝了变量的内存地址,深拷贝拷贝了变量的内容。提... 查看详情

ios静态库和动态库打包framework流程(纯swift版/swift、oc混编版)

...最后,将XX.framework(真机或者模拟器framework都可)文件夹拷贝出来,替换AILLSDK(本文使用的)为刚才合并的新文件。查看替换后的framework支持全部真机模拟器架构。我在合并binary文件之后,仅拷贝出Release-iphoneos文件夹下的XXX.framewo... 查看详情

swift与oc混编

...新建一个Swift类型的工程,由于种种原因,里面会有一些OC类,OC类用到了项目中的某些Swift类,而Swift类又用到了这些OC类,怎么解决?解答其实,Swift和OC文件是可以共存在一个工程中的,我们只需要简单的配置,和一些注意细... 查看详情

objective-c中mutablecopy和copy的理解

参考技术A深拷贝(mutableCopy)就是内容拷贝,即指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉;浅拷贝(copy)就是指针拷贝,... 查看详情

oc数据类型

OC是增强了C的特性,所以在变量和基本数据类型上基本与C一致。在OC中变量命名有如下规则:由字母、数字、下划线、$符号组成必须以字母、下划线、$符号开头大小写敏感在OC中定义变量的时候不能使用OC的保留字,OC的保留字... 查看详情

oc语言关闭指定程序

...m函数,调用dos命令taskkill实现关闭正在运行的应用程序。OC语言的全名是ObjectC编程语言,在程序员的领航里,我们通常简称为OC语言。OC语言是基于C语言基础上,在进行了一次更高级的封装的一门语言,它的底层实现是基于C语言... 查看详情

oc与swift混编杂记

今天使用在swift项目上使用了oc项目的一部分源代码发现了以下问题:1.oc无法继承swift类2.oc无法使用纯swift类3.带有闭包的函数无法被oc类调用以上问题使得oc使用swift源码变得困难重重 昨天打包的时候发现这个问题:“Undefined... 查看详情

oc5--方法

//main.m//第一个OC类-方法2#import<Foundation/Foundation.h>//1.编写类的声明@interfaceIphone:NSObject{@publicfloat_model;int_cpu;double_size;int_color;}//注意:OC中的方法,如果没有形参不需要写(),而是直接写一个;因为OC方法中的()有特殊的用途,OC方法中... 查看详情

oc4--方法

//main.m//第一个OC类-方法2#import<Foundation/Foundation.h>//1.编写类的声明@interfaceIphone:NSObject{@publicfloat_model;int_cpu;double_size;int_color;}//注意:OC中的方法,如果没有形参不需要写(),而是直接写一个;因为OC方法中的()有特殊的用途,OC方法中... 查看详情

oc与swift相互调用

 一、OC调用swift文件二、swift调用OC文件三、注意和总结添加:四、自定义桥接文件 一、OC调用swift文件  在OC项目中创建一个swift文件的时候,Xcode会提示需要创建一个桥接文件,点确定创建桥接文件,Xcode会自动创建一... 查看详情

项目里面swift和oc交叉使用

在OC的项目中使用Swift语言开发创建swift文件,同时创建桥接文件。(桥接文件里面不用导入头文件)在swift文件中完成代码的编写。在某OC类的.m文件中,使用swift文件。方法;#import"OC工程的产品名-Swift.h"<固定的,不要乱写>头文... 查看详情

李洪强ios开发之oc语言前期准备

OC语言前期准备 一、OC简介Oc语言在c语言的基础上,增加了一层最小的面向对象语法,完全兼容C语言,在OC代码中,可以混用c,甚至是c++代码。可以使用OC开发mac osx平台和ios平台的应用程序。拓展名:c语言-.c  OC... 查看详情

uiwebview中html中用js调用oc方法及oc执行js代码

HTML代码:<html><head><title>HTML中用JS调用OC方法</title><metahttp-equiv="Content-Type"content="text/html;charset=UTF-8">[removed]functionopenAlbum(){//打开相册(openMyAlbum为OC中的方法)[re 查看详情