iOS常见的几个修饰词深入讲解

更新时间:2023-05-09 07:51:05 阅读: 评论:0

iOS常见的⼏个修饰词深⼊讲解
前⾔:
最近公司在扩招,做为公司仅有的唯⼀⼀个⾸席iOS开发⼯程师(⼿动滑稽),我不得不硬着头⽪上阵。
然后却发现很多⼈的⽔平和年限严重不符,公司招的⼈都是3年+以上经验的⼈,然⽽这些⼈中有⼀半连修饰词的作⽤也说的模棱两可,加上⾃⼰⽔平也不⾼,对以后的职业⽣涯产⽣了严重的危机感,遂决定以后每周希望能写⼀篇有价值的⽂章,与君共勉,今天就说说iOS常见的⼏个修饰词。
⼀、readOnly,readWrite
readOnly:
根据字⾯意思,⼤家都很容易知道是“只读”的意思,意味着只⽣成了getter⽅法,⽽没有⽣成tter⽅法,如果这时候调⽤tter ⽅法,会报⼀个Assignment to readonly property错误
PS:这⾥顺便说⼀下lf.和_的区别
lf.就是调⽤property⾃动⽣成的getter和tter⽅法,⽽_则是直接去调⽤实例变量(property会⾃动⽣
成⼀个实例变量,如果你重写了getter与tter⽅法,property⾃动⽣成的实例变量就⽆效了,需要⼿动去申明⼀个实例变量或者⽤@@synthesize).
回到正题,那么这意味着我们就完全没办法去修改readOnly的属性了吗?不然,如果你尝试⼀下tValue:forKey:,你就会发现竟然改变成功了,amazing,让我们来看看代码:
@interface MyFirstClass : NSObject
@property (nonatomic, copy, readonly) NSString * string;
@end
#import "MyFirstClass.h"
@implementation MyFirstClass
- (instancetype) init{
lf = [super init];
if (lf) {
_string = @"来改变我啊";
}
return lf;
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
MyFirstClass * class = [MyFirstClass new];
NSLog(@"string === %@", class.string);
[class tValue:@"改变了" forKey:NSStringFromSelector(@lector(string))];
NSLog(@"string === %@", class.string);
}
Log如下:
2018-03-16 11:08:58.932303+0800 PropertyDesc[5681:445705] string === 来改变我啊
2018-03-16 11:08:58.932454+0800 PropertyDesc[5681:445705] string === 改变了
⽽如果这个时候在MyFirstClass⾥加⼊
@implementation MyFirstClass
- (instancetype) init{
lf = [super init];
if (lf) {
_string = @"来改变我啊";
}
return lf;
}
+ (BOOL) accessInstanceVariablesDirectly{
return NO;
}
@end
在运⾏,boom,系统会报以下错误
2018-03-16 11:19:21.619747+0800 PropertyDesc[6016:478446] *** Terminating app due to uncaught exception
'NSUnknownKeyException', reason: '[<MyFirstClass 0x6040000088f0> tValue:forUndefinedKey:]: this class is not key value coding-compliant for the key string.'
没有找到当前要赋值的属性,那么accessInstanceVariablesDirectly究竟是什么呢,我们打开苹果的官
⽅⽂档找到
在这⾥可以看到,如果这个⽅法设为YES,访问器就会去寻找名称为_<key>, _is<Key>, <key>, or is<Key>的成员变量,如果为NO,就会跳到第6步,第6步就会报[valueForUndefinedKey:]错误。
总结:
readOnly并不能完全保证只读,我们可以通过KVC尝试去修改其值。
PS:有兴趣的⼩伙伴可以尝试去修改别⼈的SDK,包括苹果爸爸的
readWrite:
这个实在没什么可说的,默认的修饰词就是readWrite,代表可读可写
⼆、nonatomic、atomic
我们先看⼀下官⽅⽂档
苹果官⽹对两者的说法
atomic:
默认的属性修饰词,按官⽅⽂档上说即使从不同的线程通过getter或tter⽅法去访问属性也能完全的获取到或设置值,从这⾥也可以看出,atomic并不是线程安全的,因为atomic只能保证通过tter和getter⽅法能获取到⼀个完整的value,如果A线程在getter,B、C线程在tter,可能A获取到的值是BC执⾏之后的值,也可能是BC线程执⾏完之前的值,也可能是B C线程任何⼀个线程执⾏完的值。
因此atomic的伪代码⼤概如下:
- (void)tString:(NSString *)string{
@synchronized(lf) {
if (_string != string) {
[_string relea];//MRC
_string = [string copy];
}
}
}
- (NSString *) string{
@synchronized(lf) {
return _ string;
}
}
nonatomic:
相对⽽⾔,通过nonatomic修饰的属性,并没有做锁的操作,多线程同时进⾏tter/getter操作,并不能保证得到⼀个完整的value,所以相对atomic来说nonatomic修饰的属性访问速度更快,⽽且平时对线程安全我们更倾向于使⽤信号量、NSLock和synchronized去控制线程安全,他们都能保证代码块的原⼦性,所以⼏乎所有的属性都⽤nonatomic去修饰。
三、assign、weak与strong
assign:
⼀般来说,我们都⽤assign去修饰OC的基本数据类型,but why?
因为assign并不会使对象的引⽤计数加1,也就是说如果⽤assign去修饰⼀个对象,这个对象会⽴即被释放,重要的是assgin 在被释放的时候是不会⾃动置为nil,还是保留对象的指针地址,会形成野指针,这个时候向其发送消息就会崩溃,简单实验的代码如下:
@interface MySecondClass : NSObject
@property (nonatomic, assign) NSMutableArray * array;
@end
- (void) testMethodTwo{
MySecondClass * class = [[MySecondClass alloc] init];
[lf.condClass.array addObject:@(0)];
}
在运⾏到最后⼀步的时候程序会崩溃报EXC_BAD_ACCESS的错误,如果打断点的话会发现在执⾏到这步的时候array还是有地址的。
weak:
如果把上⾯的代码
@property (nonatomic, assign) NSMutableArray * array;换成
@property (nonatomic, weak) NSMutableArray * array;
.这个时候程序并不会崩溃,如果你打个断点的话会发现array被⾃动置为nil,⽽OC的特性使得像nil发送消息并不会崩溃,这就是weak和assgin最⼤的区别,此外weak必须⽤于修饰对象,这和他⾃动置为nil相关,如果强⾏使⽤weak修饰基本数据类型,编译器会报⼀个⼤⼤的红⾊错误!
strong:
strong的作⽤和assign和weak恰恰相反,strong也是属性默认的修饰词,代表着被修饰的对象引⽤计数+1如果把上⾯的代码
@property (nonatomic, assign) NSMutableArray * array;换成
@property (nonatomic, strong) NSMutableArray * array;
最后⼀句代码可以解释为[NSMutableArray array]创造了⼀个对象A,此时A的引⽤计数为1,lf.condClass.array做为对象B,把A赋值给B的时候,A的引⽤计数加1,此时A的引⽤计数为2,B指向了A,然后编译器会⾃动对A进⾏释放操作(因为是局部变量),A的引⽤计数-1。在拥有B的对象不释放的时候,A的引⽤计数永远不可能为0,除⾮你⼿动释放或者把B指向⼀个新的对象,这样A永远不会被释放,这就是所谓的强引⽤。
weak和strong的区别:weak和strong不同的是当⼀个对象不再有strong类型的指针指向它的时候它会被释放,即使还有weak型指针指向它。⼀旦最后⼀个strong型指针离去,这个对象将被释放,所有剩余的weak型指针都将被清除。
copy与retain:
copy其实是建⽴了⼀个相同的对象,⽽retain不是.
copy是内容拷贝,retain是指针拷贝.
copy是内容的拷贝 ,对于像NSString,的确是这样,如果拷贝的是NSArray这时只是copy了指向array中相对应元素的指针.
这便是所谓的"浅复制".
atomic是Objc使⽤的⼀种线程保护技术,基本上来讲,是防⽌在写未完成的时候被另外⼀个线程读取,造成数据错误。⽽这种机制是耗费系统资源的,所以在iPhone这种⼩型设备上,如果没有使⽤多线程间的通讯编程,那么nonatomic是⼀个⾮常好的选择。
四、copy与mutableCopy
苹果官⽹对对象拷贝的说法
在说copy与mutableCopy之前我们先看看官⽅⽂档对深拷贝与浅拷贝的阐释,如下
深拷贝:
对象拷贝 - 重新申请⼀⽚内存保留这个对象,与原对象之间没有半点关系。
浅拷贝:
指针拷贝 - 实际上相当于引⽤计数+1,被拷贝的和拷贝的引⽤同⼀个对象。
接下来我们分两个⽅⾯做测试:
1.对⾮集合类对象的copy操作,以NSString为例
对immutableObject做copy操作
NSString * string = [NSString stringWithFormat:@"1"];
NSString * copyString = [string copy];
NSString * mutableCopyString = [string mutableCopy];
NSLog(@"string:%p", string);
NSLog(@"copyString:%p", copyString);
NSLog(@"mutableCopyString:%p", mutableCopyString);
Log如下:
2018-03-19 15:51:38.785253+0800 PropertyDesc[10283:759804] string:0xa000000000000311
2018-03-19 15:51:38.785435+0800 PropertyDesc[10283:759804] copyString:0xa000000000000311
2018-03-19 15:51:38.785518+0800 PropertyDesc[10283:759804] mutableCopyString:0x608000055150
可以看出对string和copyString的地址是⼀样的,⽽mutableCopyString则不同。
对mutableObject做copy操作
NSMutableString * string = [NSMutableString stringWithFormat:@"1"];
NSString * copyString = [string copy];
NSString * mutableCopyString = [string mutableCopy];
NSLog(@"string:%p - %@", string, string);
NSLog(@"copyString:%p - %@", copyString, copyString);
NSLog(@"mutableCopString:%p - %@", mutableCopyString, mutableCopyString);
[string appendString:@",2"];
NSLog(@"copyString:%p - %@", copyString, copyString);
NSLog(@"mutableCopString:%p - %@", mutableCopyString, mutableCopyString);
Log如下:
2018-03-19 15:51:38.785670+0800 PropertyDesc[10283:759804] string:0x60400005a940 - 1
2018-03-19 15:51:38.785784+0800 PropertyDesc[10283:759804] copyString:0xa000000000000311 - 1
2018-03-19 15:51:38.785834+0800 PropertyDesc[10283:759804] copyString:0xa000000000000311 - 1
2018-03-19 15:51:38.785891+0800 PropertyDesc[10283:759804] mutableCopyString:0x60400005a
910 - 1
2018-03-19 15:51:38.786037+0800 PropertyDesc[10283:759804] mutableCopyString:0x60400005a910 - 1
可以看出对string与copyString、mutableCopyString三者的地址都是不同的。
即使改变了原string的value,copyString与mutableCopystring也没有改变,这与下⽂对集合类对象得出的结论正好相反。结论:
对 immutableObject进⾏ copy 操作是指针拷贝,mutableCopy 操作时对象拷贝。
对 mutable Object进⾏ copy 和 mutableCopy 都是对象拷贝。简单的表格图如下:
Object Handle Result
immutableObject copy指针拷贝
immutableObject mutableCopy深拷贝
mutableObject copy深拷贝
mutableObject mutableCopy深拷贝
2.对集合类对象的copy操作
对immutableObject做copy操作
NSArray * array = [NSArray arrayWithObject:@"1"];
NSArray * copyArry = [array copy];
NSMutableArray * mutableCopyArray = [array mutableCopy];
NSLog(@"array:%p", array);
NSLog(@"copyArry:%p", copyArry);
NSLog(@"mutableCopyArray:%p", mutableCopyArray);
Log如下
2018-03-19 15:51:38.786167+0800 PropertyDesc[10283:759804] array:0x6000000094c0
2018-03-19 15:51:38.786278+0800 PropertyDesc[10283:759804] copyArray:0x6000000094c0
2018-03-19 15:51:38.786385+0800 PropertyDesc[10283:759804] mutableCopyArray:0x600000240030
可以看出array与copyArray的地址是⼀样的,⽽mutableCopyArray则不同。
对mutableObject做copy操作
NSMutableString * string = [NSMutableString stringWithFormat:@"1"];
NSMutableArray * array = [NSMutableArray arrayWithObject:string];
NSArray * copyArry = [array copy];
NSMutableArray * mutableCopyArray = [array mutableCopy];
NSLog(@"array:%p", array);
NSLog(@"copyArry:%p", copyArry);
NSLog(@"mutableCopyArray:%p", mutableCopyArray);
[array addObject:@"2"];
[string appendString:@"1"];
NSLog(@"array:%p - %@", array, array);
NSLog(@"copyArry:%p - %@", copyArry, copyArry);
NSLog(@"mutableCopArray:%p - %@", mutableCopyArray, mutableCopyArray);
Log如下
2018-03-26 13:36:38.786499+0800 PropertyDesc[10283:759804] array:0x600000240150
2018-03-26 13:36:38.786600+0800 PropertyDesc[10283:759804] copyArry:0x6000000095f0
2018-03-26 13:36:38.786698+0800 PropertyDesc[10283:759804] mutableCopyArray:0x6000002400f0
2018-03-26 13:36:38.786865+0800 PropertyDesc[10283:759804] array:0x600000240150 - (
11,
2
)
2018-03-26 13:36:38.787018+0800 PropertyDesc[10283:759804] copyArry:0x6000000095f0 - (
11
)
2018-03-26 13:36:38.787142+0800 PropertyDesc[10283:759804] mutableCopyArray:0x6000002400f0 - (
11
)
What??不管是copy还是mutableCopy我们可以看到当我们修改了string的值后,数组中的值都变了,但是在 [array addObject:@"2"];的时候两个复制出来的数组的对象并没有变化?
这⾥我们要提到⼀个新概念不完全深拷贝(也有⼈说是单层深拷贝)------ 即虽然新开辟了内存地址,
但是存放在内存上的值(也就是数组⾥的元素仍然指向原数组元素值,并没有另外复制⼀份),所以说上⽂中的array和mutableCopArray类似于有⼀个或多个相交点的相交链表。
⽽且我们也可以看到不管是copy还是mutableCopy都是不完全深拷贝,三者的地址都是不⼀样的。
结论:
对immutableObject做copy是指针拷贝,做mutableCopy是不完全深拷贝。
对mutableObject做copy或mutableCopy都是不完全深拷贝。
有趣的是,这与上⽂的结论有类似之处。简单的表格图如下:
Object Handle Result
immutableObject copy指针拷贝
immutableObject mutableCopy不完全深拷贝
mutableObject copy不完全深拷贝

本文发布于:2023-05-09 07:51:05,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/101747.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:对象   拷贝   指针   时候   没有   线程
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图