iOS之copy、strong使用,block特性
身边一同事,我印象在过去三个月,有两次因为使用“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:
- _NSConcreteGlobalBlock 全局的静态 block,不会访问外部局部变量。
- _NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
- _NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。
关于block的知识,参考http://blog.devtang.com/2013/07/28/a-look-inside-blocks/
iOS之copy、strong使用,block特性的更多相关文章
- 【转】iOS 浅谈:深.浅拷贝与copy.strong
深.浅拷贝 copy mutableCopy NSString 1 2 3 4 5 6 NSString *string = @"汉斯哈哈哈"; // 没有产生新对象 NSStri ...
- iOS中copy和strong修饰符的区别
iOS中copy和strong修饰符的区别 //用copys修饰的生成的都是不可变的对象 ,如果调用可变类型方法的直接报错 @property(nonatomic,copy)NSString * cp ...
- iOS 浅谈:深.浅拷贝与copy.strong
深.浅拷贝 copy mutableCopy NSString NSString *string = @"汉斯哈哈哈"; // 没有产生新对象 NSString *copyStri ...
- iOS开发 - OC - block的详解 - 深入篇
深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...
- 最新iOS 6 in Xcode4.5新特性——Storyboard和属性自动绑定
最新iOS 6 in Xcode4.5新特性编程之二(上)——Storyboard和属性自动绑定 从Xcode 4.3开始,Storyboard 就是iOS 5和iOS 6中令人兴奋的一个新特性,他将 ...
- iOS底层原理总结 - 探寻block的本质(一)
面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...
- iOS开发 - OC - block的详解 - 基础篇
深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...
- iOS retain、strong、weak、assign
iOS retain.strong.weak.assign strong与weak是由ARC新引入的对象变量属性xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和a ...
- 对于atomic nonatomic assign retain copy strong weak的简单理解
atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作 1)atomic 设置成员变量的@property属性时,atomic是默认值,提供多线程安全 在多线程环 ...
随机推荐
- Python之路-操作系统&网络基础
一.为何要有操作系统 没有操作系统的话,计算机同样可以运行,但是程序员要了解到计算机底层各种各样的细节,而操作系统聪明地封装起来了底层这些繁杂的操作,通过向程序员开放一个个的接口,来最终使我们实现对底 ...
- Android查看stdout 和stderr
在默认状态下,Android系统有stdout和stderr(System.out和System.err)输出到/dev/null,在运 行Dalvik VM的进程中,有一个系统可以备份日志文 ...
- "!function",自执行函数表达式
如题为自执行函数表达式.在这种情况下,解析器在解析function关键字的时候,会将相应的代码解析成function表达式,而不是function声明.下面2个括弧()都会立即执行 (function ...
- SpringMVC基础学习(二)—开发Handler
一.Handler开发 Handler的开发方式在springmvc中有多种,下面我们主要讲解三种实现方式:实现Controller接口.实现HttpRequestHandler接口. ...
- 08 Noise and Error
噪声:误标.对同一数据点的标注不一致.数据点信息不准确... 噪声是针对整个输入空间的. 存在噪声的情况下,VC bound依旧有用: 存在噪声,就是f--->p(y|x),f是p的特殊情况:如 ...
- JavaScript Array 技巧
filter():返回该函数会返回true的项组成的数组 ,,,,]; var result = num.filter(function(item,index,array){ ); }) consol ...
- 将1、2、3、……、n这n个连续自然数分成g组,使每组的和相等。g组中个数最多的一组有几个?
<style type="text/css"> #content { width: 600px; margin: 150px auto 0 auto; } dl dd ...
- Python多层目录模块调用
一. 引用模块在 父+级目录中: 1. 将导入模块所在目录(../model/模块)添加到系统环境变量path下,可添加多个 import syssys.path.append("../mo ...
- STM32学习笔记(二)——串口控制LED
开发板芯片:STM32F407ZGT6 PA9-USART1_TX,PA10-USART1_RX; PF9-LED0,PF10-LED1; 一.串口1配置过程(不使用串口中断): 1.使能时钟,包括G ...
- 聊聊 Tomcat 的单机多实例
Tomcat 从何而来? 先说 Tomcat 这一单词解释,如果你不是一个开发者,当然它在美国口语中并非是褒义词:如果你是开发者,那你一定听过 Web 应用服务器.Sun 公司和 Tomcat .如你 ...