修饰符weak引发的思考

2019-04-17  本文已影响0人  米斯特卢
背景

      在测试中发现有个网页没有加载出来,查找原因时,发现是由于用了weak修饰了一个NSURL的全局变量,出了方法作用域之后,这个NSURL的全局变量的值就变为nil了,因此网页才没能加载成功。

思考和实践

      对于weak这个修饰符,之前并没有做的太多的学习和研究,只是知道在修饰UI控件以及代理的时候使用。
      做了一个简单的测试,分别用weak修饰NSArrayNSMutableArrayNSDictionaryNSMutableDictionaryNSURL,其中数组和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修饰数组
  1. 当源对象为不可变数组时,不管是可变还是不可变数组,使用copystrong进行修饰时,最终数组都会变为不可变数组,内存地址不变。
  2. 当源对象为可变数组时
@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
  1. 当源对象为不可变时,使用copy时不会生成新的对象,即指针拷贝(浅拷贝);使用mutableCopy会生成一个新的可变对象,即对象拷贝(深拷贝)。
  2. 当源对象为可变时,使用copymutableCopy时都会生成一个新的对象,即对象拷贝(深拷贝),区别在于:使用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方法

iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析)

上一篇下一篇

猜你喜欢

热点阅读