码迷,mamicode.com
首页 > 其他好文 > 详细

Objective-C Objective-C中的指针,及对象的直接指向,copy和mutablecopy

时间:2015-12-01 01:43:46      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:

1.Objective-C的指针世界

OC一直是人感觉比较变态的一门语言,为什么呢?因为它的每个变量都是指针型,多的都几乎让人忘了那个*的存在了。

所以常常a=b这个等号让我产生错觉,总以为a从b那拷贝了一份。

然而这的的确确,却是个指针。a这个变量存的内容是b所在的地址。

比如我定义了一个Student的Class,new了stu1和stu2,并把stu2=stu1,那当两者任何一个进行修改时,两个变量的内容都会修改。

    Student *stu1=[[Student alloc]init];
    stu1.name=@"stu1";
    Student *stu2=stu1;
    stu2.name=@"stu2";
    NSLog(@"STU1:%@----STU2:%@",stu1.name,stu2.name);//输出两个都是stu2

在C/C++语言里,不习惯用指针作变量的情况下,当然两者是不一样的,实际上=等于号是做了一份拷贝。

    Student stu1;
    stu1.name="stu1";
    Student stu2=stu1;
    stu2.name="stu2";
    cout<<"stu1:"<<stu1.name<<" stu2:"<<stu2.name<<endl;//输出前者stu1,后者stu2

 但是上面的情况创建的是C/C++语言里所谓的栈对象,但栈的大小很有限,在创建堆对象(指针对象)的情况下,就和OC十分相似了

(然而教科书里教我们创建的貌似都是栈对象)

    Student *stu1= new Student();
    stu1->name="stu1";
    
    Student *stu2=stu1;
    stu2->name="stu2";
    cout<<"stu1:"<<stu1->name<<" stu2:"<<stu2->name<<endl;//输出两个都是stu2

 在Java里面,虽然变量的创建前面没有*,但其实默认生成的也是堆对象,对象给变量赋值只是一个引用。

 

2.NSString的错觉

 但是对NSString,我们容易产生错觉,比如我这样写:

    NSString *str1=@"str1";
    NSString *str2=str1;
    str2=@"str2";
    NSLog(@"str1:%@----str2:%@",str1,str2);//输出前者str1,后者str2

 为毛str2的修改还是不影响str1呢?说好的指针呢?这是因为通过=@""方式赋值,事实上已经重新开辟了内存,然后让str2指向这个新地方,所以str2的修改肯定就不会影响str1。

可以通过输出指针所在地址和指针指向地址来进行分析:

    NSString *str1=@"str1";
    NSString *str2=str1;
    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指针地址,显示不一样,这是两个不一样的指针
    NSLog(@"str1:%p----str2:%p",str1,str2);//内容地址,显示一样,说明都指向@“str1”

    
    str2=@"str2";
    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指针地址,显示不一样,这是两个不一样的指针
    NSLog(@"str1:%p----str2:%p",str1,str2);//内容地址,显示不一样,说明str1所指内容不变,str2所指内容已经变化
    
    NSLog(@"str1:%@----str2:%@",str1,str2);//输出前者str1,后者str2

以下的方法,实际上也都并不能拷贝一份,因为编译器对此做了优化,使几个指针变量指向的同一个内存区域

    NSString *string1=@"hello";
    NSString *string2 = [[NSString alloc]initWithString:string1];  
    NSString *string3 = [NSString stringWithString:string1];

可见,NSString类变量都是遵循这样的准则:"指针A赋值给指针B,两者指向同一块内存,修改后重新指向开辟新内存",

 

3.到底有没有拷贝?浅拷贝?深拷贝?

(1)NSString到NSString的copy:(编译器做了优化,其实并无copy,跟直接指向是一样的)

即便是通过以下的Copy,实际上和上面的情况一样,也只是把str1指向地址拷贝给了str2,使它们指向了同一个@"str1"

    NSString *str1=@"aaa";
    NSString *str2=[str1 copy];
    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指针地址输出,不一样,说明指针新建了
    NSLog(@"str1:%p----str2:%p",str1,str2);//指针指向内容地址输出,是一样的,说明内容没有被拷贝

所以,在NSString给NSString赋值时,虽然地址一样,但一旦修改就会重新指向,所以任何方式相互都不会产生干扰,以下方法都是等价的,并不一定样要copy,其实直接用第一种方式比较快。

  NSString *str2=str1;
  NSString *str3 = [[NSString alloc]initWithString:str1];
  NSString *str4 = [NSString stringWithString:str1];
NSString *str5 = [str1 copy];

如果场景需要,比如为了让某个str1指向的地方销毁,要先拷贝到新地址,然后用str2指,可以对NSString进行拷贝。

(2)NSString到NSString的拷贝:

    NSString *str1=@"aaa";
    NSString *str2=[str1 mutableCopy];
    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指针地址输出,不一样,说明指针新建了
    NSLog(@"str1:%p----str2:%p",str1,str2);//指针指向内容地址输出,是不一样的,说明重新开辟了内存,把str1的内容拷贝到新内存,str2变量指向这个新地址

 

(3)NSMutableString到NSString的直接指向:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
    NSString *str=mStr;
    NSLog(@"mstr:%p-----str:%p",mStr,str);//指针指向内容地址一样,说明mStr的改变会联动str
    [mStr appendString:@"def"];
    NSLog(@"mstr:%@-----str:%@",mStr,str);//mStr的改变影响了str

 这种情况,mStr的改变会影响str,但str改变就会重新指向,并不会影响mStr

(4)NSMutableString到NSString的拷贝:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
    NSString *str=[mStr copy];//NSString *str=[mStr mutableCopy];也能实现
    NSLog(@"mstr:%p-----str:%p",mStr,str);

如果不希望mStr改变影响str,可以对mStr的内容进行拷贝。

但这里面,[mStr copy]和[mstr mutableCopy],虽然都对原mStr进行了拷贝,开辟了新内存区域,但区别在于前者拷贝的对象是不可变的,后者的是可变的。可变字符串赋值给NSString其实也就丧失动态性了。

(5)NSMutableString到NSMutableString的指向:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
    NSMutableString *mStr2=mStr;
    NSLog(@"mstr:%p-----mstr2:%p",mStr,mStr2);
    [mStr appendString:@"def"];
    NSLog(@"mstr:%@-----mstr2:%@",mStr,mStr2);

 这种情况当然是两者改变都会互相影响了。

(6)NSMutableString到NSMutableString的拷贝:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
    NSMutableString *mStr2=[mStr mutableCopy];
    NSLog(@"mstr:%p-----mstr2:%p",mStr,mStr2);//指针内容地址不一样,说明实现了拷贝
    [mStr2 appendString:@"def"];
    NSLog(@"mstr:%@-----mstr2:%@",mStr,mStr2);//互不相干

 此种方式实现了对NSMutableString的拷贝,产生两个互不相干的可变字符串。

那如果通过copy来拷贝,返回不可变字符串赋值给可变的mStr2会怎么样?

    NSMutableString *mStr2=[mStr copy];

 没错,会崩掉的。

同样,用NSString给NSMutableString赋值的都是作死行为

    NSString *str1=@"str1";
    NSMutableString *mStr=[str1 copy];
    [mStr appendFormat:@"abc"];

同样崩。 

 

总结一下:

在NSString和NSMutableString中:

不变赋给不变,必须Mutablecopy才能完成真正的拷贝。

可变赋给不变,直接指向,不变会随可变而变,copy和mutablecopy都能完成拷贝。

不变赋给可变,无论什么指向拷贝方法都是作死行为,必须调stringWithString函数初始化

可变赋给可变,只有Mutablecopy才能真正的拷贝,copy作死。

 

Objective-C Objective-C中的指针,及对象的直接指向,copy和mutablecopy

标签:

原文地址:http://www.cnblogs.com/rayshen/p/5007758.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!