身边一同事,我印象在过去三个月,有两次因为使用“copy”修饰UIKit控件的属性,导致程序崩溃。他还一本正经的说我以前一直使用copy。

好了,到这里我们就不得不说说什么时候使用copy。我的印象中,只有两处使用了copy,即修饰NSString类型与block,其他的都是使用strong关键字修饰。

说到这里,我们先来说说NSString类型,我在创建的NSString类型的属性中,也曾也使用过strong修饰的,因为我几乎没有使用过NSMutableString类型转换,我不用去考虑是用copy还是strong更好,当然为了代码的健壮使用copy更好,一下我就作具体分析缘由。

在MRC中,使用retain,copy进行拷贝,会使retainCount结果+1.但是如果是深拷贝,便会改变指针,retainCount = 1;下面我直接在ARC下调试,我只关心内存指针,不关心retainCount。

NSString *str0 = @"a";

NSLog(@"str0内存地址: %p",str0);    //0x107fcb088   在64位系统上得到的内存地址较短,说明存放在常量区(代码,常量,全局,堆,栈)

NSString *string0  = [str0 copy];

NSLog(@"string0的内存地址: %p",string0);   //0x107fcb088  浅拷贝

NSString *str = [NSString stringWithFormat:@"%@",@"a"];

NSLog(@"str内存地址: %p",str);   //0xa000000000000611  (栈区)

NSString *string  = [str copy];

NSLog(@"string的内存地址: %p",string);   //0xa000000000000611  浅拷贝

NSMutableString *str1 = [NSMutableString stringWithFormat:@"a"];

NSLog(@"str1的内存地址:%p",str1);   //0x60000007c5c0

NSMutableString *string1 = [str1 copy];

NSLog(@"string1的内存地址: %p",string1);   //0xa000000000000611   内存地址发生了改变,进行了深拷贝,而且跟上面的地址一样

总结:对于NSString类型只是引用了内存,浅拷贝;NSMutableString作为NSString的子类进行copy才是深拷贝。

刚刚上面的深拷贝,出现跟浅拷贝一样的地址,不由得我们需要多做两个测试,如下:

NSMutableString *strEx = [str mutableCopy];

NSLog(@"strEx的内存地址:%p",strEx);    //0x608000263040 深拷贝

NSMutableString *strExCopy = [str mutableCopy];

NSLog(@"strExCopy的内存地址:%p",strExCopy); //0x60000026a440    str两次mutableCopy的地址不一样

NSMutableString *stringEx = [strEx copy];

NSLog(@"stringEx的内存地址: %p",stringEx);   //0xa000000000000611 与上面地址一样

NSMutableString *stringEx1 = [strExCopy copy];

NSLog(@"stringEx1的内存地址: %p",stringEx1); //这个也是0xa000000000000611,说明两次copy都指向同一个地址

NSMutableString *strExEx = [strEx mutableCopy];

NSLog(@"strExEx的内存地址:%p",strExEx);     //0x600000073d00 深拷贝

结论:可以看成,str1所谓的“深拷贝”,其实不是“深拷贝”,它还是拷贝了之前的地址。这样,我得出,当进行mutable创建,其实是系统首先创建了一份NSString的地址,然后再深拷贝,相当于[NSMutableString stringWithFormat:@"a"];来自于 [str mutableCopy];。

在字符串类型NSString中使用strong还是copy,到底哪个更好,苹果自己的API中告诉了我,copy更好,那么我们就进一步进行验证。首先我们创建两个字符串对象分别为strong与copy修饰的,然后再进行赋值比较,如下。

@property (strong,nonatomic)NSString *testStr;

@property (copy,nonatomic)NSString *testStrCopy;

- (void)viewDidLoad {

[super viewDidLoad];

NSString *testStr = [NSString stringWithFormat:@"%@",@"a"];

NSLog(@"testStr内存地址: %p",testStr); //0xa000000000000611

self.testStr = testStr;

NSLog(@"self.testStr内存地址: %p",self.testStr);//0xa000000000000611   浅拷贝

self.testStrCopy = testStr;

NSLog(@"self.testStrCopy内存地址: %p",self.testStrCopy);//0xa000000000000611  浅拷贝

NSMutableString *testStr1 = [NSMutableString stringWithFormat:@"%@",@"a"];

NSLog(@"testStr1内存地址: %p",testStr);  //0x608000078a00  与上面的str1 0x60000007c5c0也不一样,MutableCopy是重新创建了地址

self.testStr = testStr1;

NSLog(@"self.testStr内存地址: %p",self.testStr);//0x608000078a00 strong指向同一个地址

self.testStrCopy = testStr1;

NSLog(@"self.testStrCopy内存地址: %p",self.testStrCopy);//0xa000000000000611 虽然地址变了,但还是指向原来的地址

}

总结:对于NSString类型,使用copy修饰,不会改变它原有的类型,strong会指向引用的对象,有可能改变其类型状态,所以copy能增强NSString的健壮性----------------用下面一张图表示

block特性

另一个使用copy的地方就是修饰block,对于我们现在都使用ARC模式来说,我觉得使用strong或者copy都是可以的,下面用事例说明:

@property (nonatomic,copy)void(^demoBolck)();

@property (nonatomic,strong)void(^demoBolck1)();

int b=8;

void (^demoBolck)() = ^{

NSLog(@"demoBolck");

};

NSLog(@"demoBolck %@",demoBolck);    //<__NSGlobalBlock__: 0x1085af0e0>  无论ARC还是MRC下,因不访问外部局部(包括无外部变量或者只有全局变量),NSGlobalBlock表示在全局区

void (^demoBolck4)() = ^{

NSLog(@"demoBolck4  %d",b);

};

NSLog(@"demoBolck4 %@",demoBolck4);    //<__NSGlobalBlock__: 0x10150b120>  全局区

__block int a = 6;   //block内部引用a,并修改其值,需要用block修饰,不然可以不用。不过是引用行属性,需要

void (^demoBolck2)() = ^{

NSLog(@"demoBolck2 %d",a++);

};

demoBolck2();

NSLog(@"demoBolck2 %@,%d",demoBolck2,a);   //<__NSMallocBlock__: 0x600000056c50> ARC下堆区  <__NSStackBlock__: 0x7fff5d0ada28>MRC下在栈区

NSLog(@"demoBolck2.Copy %@",[demoBolck2 copy]);    //<__NSMallocBlock__: 0x600000056c50>copy操作不管MRC或者ARC都在堆区,只是在MRC下进行copy会改变地址

self.demoBolck = demoBolck2;

NSLog(@"self.demoBolck %@",self.demoBolck);

self.demoBolck1 = demoBolck2;

self.demoBolck1();     //demoBolck2  7   能执行无问题

NSLog(@"self.demoBolck1 %@",self.demoBolck1);     //<__NSMallocBlock__: 0x600000056c50>  strong修饰并没有问题

总结:在 Objective-C 语言中,一共有 3 种类型的 block:

  1. _NSConcreteGlobalBlock 全局的静态 block,不会访问外部局部变量。
  2. _NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
  3. _NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

关于block的知识,参考http://blog.devtang.com/2013/07/28/a-look-inside-blocks/

iOS之copy、strong使用,block特性的更多相关文章

  1. 【转】iOS 浅谈:深.浅拷贝与copy.strong

    深.浅拷贝 copy mutableCopy NSString 1 2 3 4 5 6 NSString *string = @"汉斯哈哈哈"; // 没有产生新对象 NSStri ...

  2. iOS中copy和strong修饰符的区别

    iOS中copy和strong修饰符的区别 //用copys修饰的生成的都是不可变的对象 ,如果调用可变类型方法的直接报错 @property(nonatomic,copy)NSString * cp ...

  3. iOS 浅谈:深.浅拷贝与copy.strong

    深.浅拷贝 copy mutableCopy NSString NSString *string = @"汉斯哈哈哈"; // 没有产生新对象 NSString *copyStri ...

  4. iOS开发 - OC - block的详解 - 深入篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  5. 最新iOS 6 in Xcode4.5新特性——Storyboard和属性自动绑定

    最新iOS 6 in Xcode4.5新特性编程之二(上)——Storyboard和属性自动绑定 从Xcode 4.3开始,Storyboard 就是iOS 5和iOS 6中令人兴奋的一个新特性,他将 ...

  6. iOS底层原理总结 - 探寻block的本质(一)

        面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...

  7. iOS开发 - OC - block的详解 - 基础篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  8. iOS retain、strong、weak、assign

    iOS retain.strong.weak.assign strong与weak是由ARC新引入的对象变量属性xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和a ...

  9. 对于atomic nonatomic assign retain copy strong weak的简单理解

    atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作 1)atomic 设置成员变量的@property属性时,atomic是默认值,提供多线程安全 在多线程环 ...

随机推荐

  1. ceph集群安装

    所有 Ceph 部署都始于 Ceph 存储集群.一个 Ceph 集群可以包含数千个存储节点,最简系统至少需要一个监视器和两个 OSD 才能做到数据复制.Ceph 文件系统. Ceph 对象存储.和 C ...

  2. CSS盒模型和文本溢出

    CSS盒模型和文本溢出 学习目标 认识盒子模型 盒子模型的组成部分 学习盒子模型的相关元素margin padding 文本溢出相关的属性 一.认识盒子模型 盒模型是css布局的基石,它规定了网页元素 ...

  3. DynamicObject扩展--实现JSON和DynamicObject的序列化与反序列化

    度娘许久,找不到我满意的答案,于是自己东凑西凑实现一个. DynamicObject扩展--实现JSON和DynamicObject的序列化与反序列化,亲测良好. 看代码 using System; ...

  4. WPF 截屏软件开发

    最近由于工程需要开始研发基于Windows的自动录屏软件,很多细节很多功能需要处理,毕竟一个完美的录屏软件不是你随随便便就可以写出来的.首先参考了大部分的录屏软件,在研发的过程中遇到了很多的问题:比如 ...

  5. Windows入门基础:1.关于CreateWindow()函数使用中遇到的问题

    我在实现显示窗口的程序中,遇到一个问题:首先程序没有任何语法错误,编译能够通过,但是就是不能弹出窗口. 后来在MSDN中查询CreateWindow()函数,发现了下面这句话: "If lp ...

  6. Java 中的 String 类常用方法

    字符串广泛应用在Java编程中,在Java中字符串属于对象,String 类提供了许多用来处理字符串的方法,例如,获取字符串长度.对字符串进行截取.将字符串转换为大写或小写.字符串分割等. Strin ...

  7. c# 逆波兰式实现计算器

    语文不好,不太会组织语言,希望不要太在意. 如题,先简要介绍一下什么是逆波兰式  通常我们在写数学公式的时候  就是a+b+c这样,这种表达式称为中缀表达式,逆波兰式又称为后缀表达式,例如a+b 后缀 ...

  8. Spring+SpringMVC+MyBatis+easyUI整合优化篇(九)数据层优化-jdbc连接池简述、druid简介

    日常啰嗦 终于回到既定轨道上了,这一篇讲讲数据库连接池的相关知识,线程池以后有机会再结合项目单独写篇文章(自己给自己挖坑,不知道什么时候能填上),从这一篇文章开始到本阶段结束的文章都会围绕数据库和da ...

  9. cocos2d-x - C++/Lua交互

    使用tolua++将自定义的C++类嵌入,让lua脚本使用 一般过程: 自定义类 -> 使用tolua++工具编译到LuaCoco2d.cpp中 -> lua调用 步骤一:自定义一个C++ ...

  10. File Transfer

    本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师.何钦铭老师的<数据结构> 代码的测试工具PTA File Transfer 1 Question 2 Explain First, ...