标签:
NSString是不可变字符串对象,这句话的意思,结合代码:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *str = @"Shaw";
NSString *str1 = @"Root"; // NSString *str1的意思是str1指向的@"Root"对象是不可变的,但str1是可以改变指向的。
NSLog(@"str = %@, str1 = %@",str,str1);
NSLog(@"str:%p, str1:%p",str,str1);
str = [str stringByAppendingString:@"andRoot"]; // 打印可以看到str地址变了,因为原地址下的对象是不可变的。
NSLog(@"str:%p, str1:%p",str,str1);
str1 = str; // 使str1指向str对象
NSLog(@"str = %@, str1 = %@",str,str1);
NSLog(@"str:%p, str1:%p",str,str1);
}
return 0;
}
// 输出结果
2016-04-06 13:32:45.320 test[40011:4790098] str = Shaw, str1 = Root
2016-04-06 13:32:45.321 test[40011:4790098] str:0x100001050, str1:0x100001070
2016-04-06 13:32:45.321 test[40011:4790098] str:0x1001026b0, str1:0x100001070
2016-04-06 13:32:45.321 test[40011:4790098] str = ShawandRoot, str1 = ShawandRoot
2016-04-06 13:32:45.321 test[40011:4790098] str:0x1001026b0, str1:0x1001026b0
Program ended with exit code: 0
同理,NSMutableString就是可变字符串对象。
stringByAppendingString:方法的定义为:- (NSString *)stringByAppendingString:(NSString *)aString;
NSMutableString *mStr = [NSMutableString stringWithString:@"Shaw"];
NSLog(@"%@ %p",mStr,mStr);
[mStr appendString:@"andRoot"]; // 可以看到输出地址为同一个,即对当前对象做了改变。
NSLog(@"%@ %p",mStr,mStr);
// 输出结果
2016-04-06 16:17:05.789 test[40118:4806417] Shaw 0x100203470
2016-04-06 16:17:05.790 test[40118:4806417] ShawandRoot 0x100203470
Program ended with exit code: 0
如果用NSMutableString对象调用stringByAppendingString:方法会出现警告"Incompatible pointer types assigning NSMutableString to NSString"
有如下的结果:
复制不可变对象时
1. copy是浅复制,即指针复制,两个指针都指向那块空间
2. mutableCopy是深复制,即新开辟一块空间,将对象复制过去
复制可变对象时
mutableCopy与copy都是深复制,但copy返回的对象不可变
下面可以用代码一一验证:
1 // 复制不可变对象
2 NSString *str = @"Shaw";
3
4 NSString *strCopy = [str copy];
5 NSString *strMCopy = [str mutableCopy];
6 NSMutableString *mStr = [str copy];
7
8 // [mStr appendString:@"andRoot"]; //运行时crash:‘Attempt to mutate immutable object with appendString:‘
9
10
11 NSLog(@"%@:%p %@:%p %@:%p",str,str,strCopy,strCopy,strMCopy,strMCopy);
12 strCopy = [str stringByAppendingString:@"andRoot"];
strMCopy = [strMCopy stringByAppendingString:@"andRoot"];
13 NSLog(@"%@:%p %@:%p %@:%p",str,str,strCopy,strCopy,strMCopy,strMCopy);
14
15 // 输出结果
16 2016-04-06 18:06:17.399 test[40355:4843127] Shaw:0x100001050 Shaw:0x100001050 Shaw:0x100600380
17 2016-04-06 18:06:17.400 test[40355:4843127] Shaw:0x100001050 ShawandRoot:0x100103870 Shaw:0x100600380
第6行和第12行代码?
因为strCopy是NSString对象,执行第12行代码,是开辟了另一块空间(0x100103870)的,并没有改变之前那块空间(0x100001050)的对象,所以也是遵守了copy返回的对象(0x100001050)不能被改变这个规则的。
而strMCopy是NSMutableString对象,执行第6行代码,并不会开辟另一块空间,所以这行代码是不能执行成功的。
// 复制可变对象
NSMutableString *mStr = [NSMutableString stringWithString:@"Shaw"];
NSString *strMCopy = [mStr mutableCopy];
NSString *strCopy = [mStr copy];
// NSLog(@"%@:%p %@:%p %@:%p",mStr,mStr,strMCopy,strMCopy,strCopy,strCopy);
NSMutableString *mStrCopy = [mStr copy]; // 打印结果可以看出mStrCopy和strCopy其实是同一个对象,也就是说可变对象的copy只能新开一块空间出来,之后再copy也都是指向这块空间的对象。
// [mStrCopy appendString:@"andShaw"]; // 运行时crash:unrecognized selector sent to instance 0x7761685345‘
NSLog(@"%@:%p %@:%p %@:%p %@:%p",mStr,mStr,strMCopy,strMCopy,strCopy,strCopy,mStrCopy,mStrCopy);
strMCopy = [strMCopy stringByAppendingString:@"andRoot"]; // 会放在新地址
strCopy = [strCopy stringByAppendingString:@"andRoot"]; // 会放在新地址
NSLog(@"%@:%p %@:%p %@:%p",mStr,mStr,strMCopy,strMCopy,strCopy,strCopy);
// 输出结果
2016-04-06 19:15:09.413 test[40489:4866634] Shaw:0x100400290 Shaw:0x1004004d0 Shaw:0x7761685345 Shaw:0x7761685345
2016-04-06 19:15:09.414 test[40489:4866634] Shaw:0x100400290 ShawandRoot:0x100400900 ShawandRoot:0x100400550
其实复制不可变对象,没有太大必要去使用mutableCopy,因为反正你都改变不了它的值。
weak strong是ARC引入的关键词。
strong指针
NSString *firstName = @"Ray";
firstName这个strong指针拥有@"Ray"对象
此时猜想一个textField,当输入Ray
self.textField.text = @"Ray";
此时有两个strong指针指向此对象
textField中的文字变化 变成Rayman
此时就变成上图的样子
只有当firstName被赋予新值,或者含有此局部变量的方法结束,或者因为firstName是一个实例变量且它所属的那个对象已经deallocated,这种所有权才结束。
当@"Ray"不再被任何强指针拥有,它就被释放了。
把firstName和self.textField.text这种指针称为strong指针,因为它们使对象存在于内存中。
默认情况下的实例变量,局部变量都是强指针。
weak指针
__weak *NSString weakName = self.textField.text; // weak指针是需要显式声明的,用__weak关键字
weakName指向对象但并没有拥有它,如果textField内容发生变动,那么@"Rayman"对象不再被任何强指针指向,它会被释放掉。
weak比assign多了一个作用就是当它指向的对象已经被销毁了,它会自己置成nil。
这是非常方便的,因为这防止弱指针继续指向那片已经被释放了的空间,曾经因为这个问题造成了很多bug,你也许有听过"悬摆指针""野指针",但是有了weak指针,这些问题不会出现了。
weak指针多数被用到有父子关系的两个对象上,父对象用strong指向子对象,子对象用weak指向父对象,这样就避免了内存循环,下面是一个例子。
如果是从storyboard中连了线到代码块的,那都是添加到了父视图的子视图树里的,也就是说是有父对象的强指针指向的
1 //
2 // ViewController.h
3 // test2
4 //
5 // Created by Shaw on 16/4/6.
6 // Copyright © 2016年 Shaw. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface ViewController : UIViewController
12
13 @property (weak, nonatomic) IBOutlet UITableView *tableView;
14
15 @property (nonatomic,weak) UIScrollView *scrollView;
16
17 @end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 353, 400, 200)];
_scrollView = scrollView;
[self.view addSubview:self.scrollView];
}
这几句代码可以用下图来描述:
担心scrollView对象有两个强指针指向不好释放?
scrollView变量是个局部变量,出了那个方法,就被释放掉了,之后就只有self一个强指针指向它了。
retain
retain在ARC下是不能显式写的,但是在@property(nonatomic,retain)这样写是没问题的。
retain的属性的setter是先release旧值,再retain新值:
@property (nonatomic,retain) NSString *string;
-(void)setString:(NSString *)str{
// if(str == _string){
// return;
// }
[_string release];
_string = [str retain];
}
NSString NSMutableString copy mutableCopy retain weak strong
标签:
原文地址:http://www.cnblogs.com/rootandshaw/p/5359035.html