一个对象使用copy或mutableCopy方法可以创建对象的副本

1.copy
需要实现NSCopying协议
创建出来的是不可变副本,如NSString, NSArray, NSDictionary
 
(1)不可变对象调用copy  (NSSring除外)
不会产生新的对象,而是返回对象本身,相当于retain,计数器+1
属于浅拷贝

         NSArray *arr1 = [NSArray arrayWithObjects:@"张三", @"李四", nil];
NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0
NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // NSArray *arr2 = [arr1 copy];
NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0
NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 2 <-- 浅拷贝,相当于retain, retainCount+1
NSLog(@"arr2.addr: %p", arr2); //0x1002052b0 <-- 浅拷贝,依旧指向同一个对象
NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 2 <-- 浅拷贝,还是原来对象的retainCount
 
(2)可变对象调用copy (NSMutableString会拷贝出一个NSString”常量对象")
返回一个不可变对象,但是不是原来的对象,属于深拷贝
         NSMutableArray *arr1 = [NSMutableArray array];
[arr1 addObject:@""];
[arr1 addObject:@"abc"];
NSLog(@"arr1.addr: %p", arr1); // 0x100204840
NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // NSMutableArray *arr2 = [arr1 copy];
NSLog(@"arr1.addr: %p", arr1); // 0x100204840
NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持
NSLog(@"arr2.addr: %p", arr2); // 0x100300000 <-- 深拷贝,开辟了新的内存空间,拷贝出来的实际对象是NSArray
NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 1 <-- 深拷贝,新的对象retainCount独立
 
(3)重点: NSString的特殊性
由于使用了 @“” 进行初始化,数据存放在了常量池
 
因为NSString指向字符串常量,系统不会收回,也不会对其作引用计数,即使我们对NSString变量如何retain或release,retainCount都是-1 (无符号最大值)
         NSString *str1 = [[NSString alloc] initWithString:@"abc"];
NSLog(@"str1.addr: %p", str1); // 0x100001030
NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存 NSString *str2 = [str1 copy];
NSLog(@"str1.addr: %p", str1); // 0x100001030
NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
NSLog(@"str2.addr: %p", str2); // 0x100001030 <-- 拷贝之后的变量依旧指向原来的常量
NSLog(@"str2.retainCount: %ld", str2.retainCount); // -1 <-- 原来常量的retainCount [str1 retain];
NSLog(@"after retain -> str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
[str2 release];
NSLog(@"after release -> str2.retainCount: %ld", str2.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
 
要使一个NSString变量也有retainCount:
就要是指向另外一个”NSString”对象,而不是字符串常量
         // 先创建出一个NSString对象,再用另一个指向
NSString *str1 = [NSString stringWithFormat:@"abc"];
NSLog(@"%ld", str1.retainCount); // -1
NSString *str2 = [NSString stringWithString:str1];
NSLog(@"%ld", str2.retainCount); //
 
(4)copy出来的是不可变对象,如NSMutableString调用copy创建出来的实际是NSString
         // 这里不能使用 NSMutableString *mstr1 = @"abc", 或者在延迟赋值 mstr1 = @"abc"; 否则同样指向常量池
NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];
NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990
NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // NSMutableString *mstr2 = [mstr1 copy];
NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990
NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持
NSLog(@"mstr2.addr: %p", mstr2); // 0x63626135 <-- 深拷贝,开辟了新的内存空间,但是指向的实际是一个字符串常量
NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // -1 <-- 因为其实拷贝出来的是一个字符串常量
2.mutableCopy
需要实现NSMutableCopying协议
创建的是可变副本,如NSMutableString, NSMutableArray, NSMutableDictionary
 
(1)不可变对象调用mutableCopy
产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
         NSString *str1 = [[NSString alloc] initWithString:@"abc"];
NSLog(@"str1.addr: %p", str1); // 0x100001030
NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存 NSMutableString *mstr2 = [str1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象
NSLog(@"str1.addr: %p", str1); // 0x100001030
NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 对于字符串常量, 无论是copy, retain, release操作都不会改变retianCount
NSLog(@"mstr2.addr: %p", mstr2); // 0x100106460 <-- 深拷贝,开辟新的空间
NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1 <-- 由于是NSMutableString对象,retainCount == 1
 
(2)可变对象调用mutableCopy
产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];
NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910
NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // NSMutableString *mstr2 = [mstr1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象
NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910
NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); //
NSLog(@"mstr2.addr: %p", mstr2); // 0x100300e90 <-- 深拷贝,开辟新的空间
NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); //
 
3.自定义类的copy
 @interface Student : NSObject

 //copy代表setter会release旧对象,copy新对象
@property (nonatomic, copy) NSString *name; @end
 
传入外部NSMutableString对象到student的setter,当外部对象改变的时候,不会改变student中copy来的对象
如果使用retain或者assign,就会影响,因为指向的是同一个对象
==>传入NSMutableString时(成员变量为NSString),一般使用copy策略,其他使用retain
 
(1)实现<NSCopying>
(2)实现 - (id) copyWithZone:(NSZone *) zone
 - (id)copyWithZone: (NSZone *) zone
{
Student *stu = [[Student allocWithZone:zone] init];
stu.name = self.name;
return stu;
}
 
 

[OC Foundation框架 - 17] copy语法的更多相关文章

  1. OC Foundation框架—集合

    Foundation框架—集合 一.NSArray和NSMutableArray (一)NSArray不可变数组 (1)NSArray的基本介绍 NSArray是OC中使用的数组,是面向对象的,以面向 ...

  2. OC Foundation框架—结构体

    一.基本知识 Foundation—基础框架.框架中包含了很多开发中常用的数据类型,如结构体,枚举,类等,是其他ios框架的基础. 如果要想使用foundation框架中的数据类型,那么包含它的主头文 ...

  3. OC Foundation框架—字符串

    一.Foundation框架中一些常用的类 字符串型: NSString:不可变字符串 NSMutableString:可变字符串 集合型: 1) NSArray:OC不可变数组 NSMutableA ...

  4. iOS - OC Foundation 框架

    前言 框架是由许多类.方法.函数和文档按照一定的逻辑组织起来的集合,以使研发程序更容易. Foundation 框架:为所有程序开发奠定基础的框架称为 Foundation 框架. Cocoa :是指 ...

  5. [OC Foundation框架 - 20] 统计代码行数

    注意: 1.变量名和函数名不要混淆调用 2.不要对文件夹进行文件的操作,没有权限 3.递归调用注意初始化变量   // // main.m // CodeLineCount // // Created ...

  6. OC — (Foundation框架-NSDate)

    NSDate:是OC中处理日期时间的一个类,可以用来表示时间 获取当前的时间 NSDate *d = [NSDate date]; 创建日期时间对象 NSLog输出是当前时间 格林时间 格式化显示时间 ...

  7. [OC Foundation框架 - 23] 文件管理

    A. 目录管理 NSFileManager*manager = [NSFileManagerdefaultManager];//单例模式 // 1.获取文件属性 NSString *path = @& ...

  8. [OC Foundation框架 - 15] NSDate

    日期处理类 定义 时间间隔计算 时间比较,返回其一 时间格式化 void dateCreate() { //date return current time NSDate *date = [NSDat ...

  9. [OC Foundation框架 - 13] NSValue

    NSNumber能够包装基本数据类型称为OC对象,是因为继承了NSValue 包装结构体成OC对象 1.自带结构体 void value() { CGPoint point = CGPointMake ...

随机推荐

  1. MVC开发过程中的疑难杂症

    MVC使用客户端验证 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type=& ...

  2. Java经典书籍

    Java Web开发教程---孙霞JSP应用开发详解(第三版)---刘晓华.张健.周慧贞Spring in Action---Craig Walls精通Struts基于MVC的Java Web设计与开 ...

  3. c# 可访问性级别

    使用访问修饰符 public.protected.internal 或 private 可以为成员指定以下声明的访问级别之一.   声明的可访问性 含义 public 访问不受限制. protecte ...

  4. 130. Surrounded Regions

    题目: Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is capt ...

  5. SOCKS5协议

    SOCKS5 是一个代理协议,这种协议对本身所代理的内容并不关心,可用于穿越防火墙. 例如我有一台web服务器,用户可以登陆上去查询公司的关键数据,这样的服务器我肯定是不想放到公网上让别人能随便访问, ...

  6. mysql 闪回表工具

    use HTTP::Date qw(time2iso str2time time2iso time2isoz); use POSIX; my $SDATE = strftime("%Y-%m ...

  7. Git教程(8)Git几种工作方式

    1,集中共享式(1个仓库) 其中角色: 1个远程仓库,N个开发者. 工作方式: 集中式系统:所有开发者共享同一个远程仓库.每次推送数据到远程仓库时都要先更新一下. 利用 Git 的分支模型,通过同时在 ...

  8. chrome渲染hover状态tranform相邻元素抖动bug

    最近同事在使用 css3 的 transition + tranform 的时候影响了相邻的元素出现bug.或者说相邻的元素出现抖动bug. 然而把 hover 状态的 tranform 属性删了后, ...

  9. 先前设定的sa密码忘记了,如何修改sa密码?

    在window身份验证登陆后,新建查询,输入以下代码就可以修改sa密码了: use master go exec sp_password null,'123456','sa' go

  10. class属性添加多个类

    <html> <head> <style type="text/css"> h1.intro { color:blue; text-align: ...