修饰符weak引发的思考
2019-04-17 本文已影响0人
米斯特卢
背景
在测试中发现有个网页没有加载出来,查找原因时,发现是由于用了weak
修饰了一个NSURL
的全局变量,出了方法作用域之后,这个NSURL
的全局变量的值就变为nil
了,因此网页才没能加载成功。
思考和实践
对于weak
这个修饰符,之前并没有做的太多的学习和研究,只是知道在修饰UI控件以及代理的时候使用。
做了一个简单的测试,分别用weak
修饰NSArray
、NSMutableArray
、NSDictionary
、NSMutableDictionary
、NSURL
,其中数组和URL
在另一个方法中调用是都为nil
了,但字典仍可以正常的存取值。至于为什么会出现这种结果,不得而知,如果有哪位小伙伴知道原理还请在评论区留言。对于OC中的对象建议还是使用strong
或者copy
进行修饰,以免因为变量为nil
而引起不必要的问题。
变量声明
@property(nonatomic,weak)NSArray * weakArray;
@property(nonatomic,weak)NSMutableArray * weakMutableArray;
@property(nonatomic,weak)NSDictionary * weakDictionary;
@property(nonatomic,weak)NSMutableDictionary * weakMutableDictionary;
@property(nonatomic,weak)NSURL * weakUrl;
运行结果
NSArray * weakArray = [NSArray arrayWithObject:@"weakArray"];
self.weakArray = weakArray;
NSLog(@"viewDidLoad方法中 weakArray = %@ %p",self.weakArray,self.weakArray);// viewDidLoad方法中 weakArray = (weakArray) 0x600003534a10
NSMutableArray * weakMutableArray = [NSMutableArray arrayWithObject:@"weakMutableArray"];
self.weakMutableArray = weakMutableArray;
NSLog(@"viewDidLoad方法中 weakMutableArray = %@ %p",self.weakMutableArray,self.weakMutableArray);//viewDidLoad方法中 weakMutableArray = (weakMutableArray) 0x60000396e130
NSLog(@"字典");
NSDictionary * weakDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"weakDictionary",@"weak",nil];
self.weakDictionary = weakDictionary;
NSLog(@"viewDidLoad方法中 weakDictionary = %@ %p",self.weakDictionary,self.weakDictionary);//viewDidLoad方法中 weakDictionary = {weak = weakDictionary;} 0x6000022611c0
NSMutableDictionary * weakMutableDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"weakMutableDictionary",@"weak",nil];
self.weakMutableDictionary = weakMutableDictionary;
NSLog(@"viewDidLoad方法中 weakMutableDictionary = %@ %p",self.weakMutableDictionary,self.weakMutableDictionary);// viewDidLoad方法中 weakMutableDictionary = {weak = weakMutableDictionary;} 0x6000037701a0
NSURL * weakUrl = [NSURL URLWithString:@"weakUrl"];
self.weakUrl = weakUrl;
NSLog(@"viewDidLoad方法中 weakUrl = %@ %p",self.weakUrl,self.weakUrl);// viewDidLoad方法中 weakUrl = weakUrl 0x600001419a40
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"viewWillAppear方法中 weakArray = %@ %p",self.weakArray,self.weakArray);// viewWillAppear方法中 weakArray = (null) 0x0
NSLog(@"viewWillAppear方法中 weakMutableArray = %@ %p",self.weakMutableArray,self.weakMutableArray);// viewWillAppear方法中 weakMutableArray = (null) 0x0
NSLog(@"viewWillAppear方法中 weakDictionary = %@ %p",self.weakDictionary,self.weakDictionary);//viewWillAppear方法中 weakDictionary = {weak = weakDictionary;} 0x6000022611c0
NSLog(@"viewWillAppear方法中 weakMutableDictionary = %@ %p",self.weakMutableDictionary,self.weakMutableDictionary);// viewWillAppear方法中 weakMutableDictionary = {weak = weakMutableDictionary;} 0x6000037701a0
NSLog(@"viewWillAppear方法中 weakUrl = %@ %p",self.weakUrl,self.weakUrl);// viewWillAppear方法中 weakUrl = (null) 0x0
}
viewdidload运行结果
viewwillappear运行结果
copy和strong修饰数组
- 当源对象为不可变数组时,不管是可变还是不可变数组,使用
copy
或strong
进行修饰时,最终数组都会变为不可变数组,内存地址不变。 - 当源对象为可变数组时
- 使用
copy
修饰可变数组或者不可变数组时,即使声明的是可变数组,最终变为一个新的不可变数组,如果这时调用可变数组的方法,像addObject
、removeObject
等方法时,会导致程序崩溃,因为不可变数组没有这些方法。 - 使用
strong
修饰不可变数组时,最终数组都会变为不可变数组,内存地址不变。这时候仍然可以调用可变数组的方法,不过不能直接调用,需要强转或者使用performSelector:withObject:
这种方式。 - 使用
strong
修饰可变数组时,数组依然是可变数组,内存地址不变。
@property(nonatomic,copy)NSArray * coArray;
@property(nonatomic,copy)NSMutableArray * coMutableArray;
@property(nonatomic,strong)NSArray * strongArray;
@property(nonatomic,strong)NSMutableArray * strongMutableArray;
NSArray * array = [NSArray arrayWithObject:@"array"];
NSLog(@"%@ %p",[array class],array); // __NSSingleObjectArrayI 0x6000015937a0
self.coArray = array;
self.coMutableArray = array;
self.strongArray = array;
self.strongMutableArray = array;
NSLog(@"%@ %p",[self.coArray class],self.coArray); // __NSSingleObjectArrayI 0x6000015937a0
NSLog(@"%@ %p",[self.coMutableArray class],self.coMutableArray);// __NSSingleObjectArrayI 0x6000015937a0
NSLog(@"%@ %p",[self.strongArray class],self.strongArray);// __NSSingleObjectArrayI 0x6000015937a0
NSLog(@"%@ %p",[self.strongMutableArray class],self.strongMutableArray);// __NSSingleObjectArrayI 0x6000015937a0
NSMutableArray * mutableArray = [NSMutableArray arrayWithObject:@"mutableArray"];
NSLog(@"%@ %p",[mutableArray class],mutableArray);// __NSArrayM 0x6000019dd8c0
self.coArray = mutableArray;
self.coMutableArray = mutableArray;
self.strongArray = mutableArray;
self.strongMutableArray = mutableArray;
NSLog(@"%@ %p",[self.coArray class],self.coArray);// __NSSingleObjectArrayI 0x6000015935c0
NSLog(@"%@ %p",[self.coMutableArray class],self.coMutableArray);// __NSSingleObjectArrayI 0x600001593590
[self.coMutableArray addObject:@"coMutableArray"];// -[__NSSingleObjectArrayI addObject:]: unrecognized selector sent to instance
NSLog(@"%@ %p",[self.strongArray class],self.strongArray);// __NSArrayM 0x6000019dd8c0
NSLog(@"%@ %p",[self.strongMutableArray class],self.strongMutableArray);// __NSArrayM 0x6000019dd8c0
数组执行结果
对象的copy与mutableCopy
- 当源对象为不可变时,使用
copy
时不会生成新的对象,即指针拷贝(浅拷贝);使用mutableCopy
会生成一个新的可变对象,即对象拷贝(深拷贝)。 - 当源对象为可变时,使用
copy
和mutableCopy
时都会生成一个新的对象,即对象拷贝(深拷贝),区别在于:使用copy
生成的对象为不可变的,而mutableCopy
生成的对象是可变的。
测试代码如下:
NSString * string = @"string";
NSLog(@"string = %@ %p",[string class],string);
// __NSCFConstantString 0x10eff20a0
NSLog(@"copyString = %@ %p",[[string copy] class],[string copy]);
// __NSCFConstantString 0x10eff20a0
NSLog(@"mutableCopyString = %@ %p",[[string mutableCopy] class],[string mutableCopy]);
// __NSCFString 0x600003f8e250
NSLog(@"NSMutableString\n");
NSMutableString * mutableString = [NSMutableString stringWithString:@"mutableString"];
NSLog(@"mutableString = %@ %p",[mutableString class],mutableString);
// __NSCFString 0x600003dfa670
NSLog(@"copy_mutableString = %@ %p",[[mutableString copy] class],[mutableString copy]);
// __NSCFString 0x6000033fc340
/**
这个地方不知道为什么打印的结果是可变字符串 ,做了一个测试,调用可变字符串的appendString方法,崩溃了
NSMutableString * copy_mutableString = [mutableString copy];
[copy_mutableString appendString:@"append"];
NSLog(@"%@",copy_mutableString); // Attempt to mutate immutable object with appendString:
*/
NSLog(@"mutableCopy_mutableString = %@ %p",[[mutableString mutableCopy] class],[mutableString mutableCopy]);
// __NSCFString 0x600003dfa940
NSLog(@"NSArray\n");
NSArray * array = [NSArray arrayWithObject:@"array"];
NSLog(@"array = %@ %p",[array class],array);
// __NSSingleObjectArrayI 0x6000031a9960
NSLog(@"copy_array = %@ %p",[[array copy] class],[array copy]);
// __NSSingleObjectArrayI 0x6000031a9960
NSLog(@"mutableCopy_array = %@ %p",[[array mutableCopy] class],[array mutableCopy]);
// __NSArrayM 0x600003dfa310
NSLog(@"NSMutableArray\n");
NSMutableArray * mutablearray = [NSMutableArray arrayWithObject:@"mutablearray"];
NSLog(@"mutablearray = %@ %p",[mutablearray class],mutablearray);
// __NSArrayM 0x600003dfdb00
NSLog(@"copy_mutablearray = %@ %p",[[mutablearray copy] class],[mutablearray copy]);
// __NSSingleObjectArrayI 0x6000031bd0a0
NSLog(@"mutableCopy_mutablearray = %@ %p",[[mutablearray mutableCopy] class],[mutablearray mutableCopy]);
// __NSArrayM 0x600003dfd710
字符串
数组
注:本文中的测试SDK版本为12.2,Xcode 10.2 ,如有错误欢迎留言指正。
参考文章
iOS内存管理(6)--NSArray与NSMutableArray用copy修饰还是strong
assign weak retain strong copy关键字的区别
整理一下OC中的那些属性修饰符
iOS Copy与MutableCopy 和 Copy与Strong 深度解析
iOS中copy和mutableCopy详解
聊聊NSString为什么用copy
iOS学习——属性引用self.xx与_xx的区别
iOS 同时重写setter和getter时候报错:Use of undeclared identifier '_name';did you mean 'name'
ios中set和get方法