ios何时使用self

来源:互联网 发布:江苏破获网络诈骗团伙 编辑:程序博客网 时间:2024/06/05 15:37

原文链接:http://blog.csdn.net/lvxiangan/article/details/27204265


从内存管理来说明使用self.和不使用self的区别:
ViewController.h文件,使用Student类,代码如下:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #import <UIKit/UIKit.h>  
  2. @class Student;  
  3.   
  4. @interface ViewController : UIViewController{  
  5.         
  6.        Student *_student;  
  7. }  
  8.    
  9. @property (nonatomicretainStudent *student;  
  10.   
  11. @end  
ViewController.m文件,代码:
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #import "ViewController.h"  
  2. #import "Student.h"  
  3.   
  4. @implementation ViewController  
  5. @synthesize student = _student;  
  6.      
  7. - (void)didReceiveMemoryWarning  
  8. {  
  9.   [super didReceiveMemoryWarning];  
  10. }  
  11.       
  12. #pragma mark - View lifecycle  
  13.     
  14. - (void)viewDidLoad  
  15. {  
  16.  [super viewDidLoad];  
  17. }  
  18.    
  19. - (void) dealloc  
  20. {  
  21.  [_student release];  
  22.  _student = nil;  
  23.  [super dealloc];  
  24. }  
其它的方法没有使用到,所以这里就不在显示了。
在ViewController.m的viewDidLoad方法中创建一个Student类的对象
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Student *mystudent = [[Student alloc] init];  
  2. self.student = mystudent;  
  3. [mystudent release];  
这是相信有人会有疑问了,问什么创建student对象要这么复杂,似乎直接使用self.student = [[Student alloc] init]; 也没有问题,不加self有时也是挺正常的呀?
接下来就需要从内存角度来分析它们之间的区别了:
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 1、加self的方式:  
  2. Student *mystudent = [[Student alloc] init];       //mystudent 对象 retainCount = 1;  
  3. self.student = mystudent;   //student 对象 retainCount = 2;  
  4. [mystudent release];  //student 对象 retainCount = 1;  
  5.   
  6. //student的property 是retain 默认使用self.student引用计数+1。  
  7.   
  8.   
  9. 2、不加self的方式  
  10. Student *mystudent = [[Student alloc] init];       //mystudent 对象 retainCount = 1;  
  11. student = mystudent;   //student 对象 retainCount = 1;  
  12. [mystudent release];   //student 对象内存已释放,如果调用,会有异常  
  13.   
  14. 3、加self直接赋值方式  
  15. self.student = [[Student alloc] init];  //student 对象 retainCount = 2;容易造成内存泄露  
由于objective-c内存管理是根据引用计数处理的,当一个对象的引用计数为零时,gcc才会释放该内存。
转载:http://jordy.easymorse.com/?p=805
 
个人总结:只需要在属性初始化的时候使用self.属性,其他时候直接使用属性名就行;使用self.是 使retaincount+1,为了确保当前类对此属性具有拥有权
个人使用习惯:
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @interface CustomClass : UIViewController  
  2. {  
  3.     NSString *str  
  4. }  
  5. @property (retainnonatomicNSString *str;  
  6.   
  7.   
  8. @implementation CustomClass  
  9. @synthesize str;  
  10.   
  11. -(void)viewDidLoad  
  12. {  
  13.     //方法一  用alloc必须手动释放一次  
  14.     self.str  =  [[NSString alloc]initWithString:@"my str"];  
  15.      [str release];  
  16.     //方法二 用类方法不用  
  17.    self.str =     [NSString stringWithString:@"my str"];  
  18.   
  19.     以后调用时直接使用str,不必使用self.str  
  20.    [str appendString:@"\n"];  
  21. }  
  22.   
  23.   
  24. //在dealloc中必须释放  
  25. - (void)dealloc  
  26. {  
  27.     //方法一  
  28.     [str release];  
  29.     str = nil;  
  30.     //方法二  
  31.     self.str = nil;  
  32.   
  33.     [super dealloc];  
  34. }          

看图:

.h文件,view2有retain参数


.m文件,

不使用self.的方法赋值


使用self.的方法赋值



使用self.的方法赋值的retaincount是对的。
@property 关键字的作用是 给实例变量在.h文件里创建一个set/get函数的申明。等同在.h文件里面给实例变量写set/get函数申明。
@property (nonatomic,retain) UIView *view2;
等于
-(UIView*)getView2;
-(void)setView2:(UIView*)view;
在.m文件里的@synthesize关键字就是自动实现set/get函数。

get方法是:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. -(MyObject*)myObject{   
  2.     return _myObject;   
  3. }   

Set方法是:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. // assign   
  2. -(void)setMyObject:(id)newValue{   
  3.     _myObject = newValue;   
  4. }   
  5. // retain   
  6. -(void)setMyObject:(id)newValue{   
  7.     if (_myObject != newValue) { // 若先前已经赋予相同的值,则不会引起计数器变化  
  8.         [_myObject release];  
  9.         _myObject = [newValue retain]; // newValue的计数器值为1,再次retain后变为2,所以self.计数器会加1   
  10.     }    
  11. }   
  12. // copy   
  13. -(void)setMyObject:(id)newValue{   
  14.     if (_myObject != newValue) { // 同上  
  15.         [_myObject release];   
  16.         _myObject = [newValue copy]; // 同上  
  17.     }   
  18. }   

retain关键字的作用是,在实现set函数内部,retain当前变量,具体实现是这样:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. -(void)setView2:(UIView*)view{  
  2.    [_view2 release];  
  3.    _view2 = [view retain];  
  4. }  

而self.view2 = tView;等于[self setView2:tview];也就是说,如果不用self.调用实例变量,retain关键字是不起作用的。

执行代码self.view2 = tView之后,tView和view2都是同一个对象,只是这个赋值的发操作把tView的retaincount+1了而已。所以当 [tView release]之后,self.view2的retaincount-1。

然后当再次给 self.view2赋值的时候,在set内部会再次release。这样是不会有内存泄露的。

在不使用self.的图片里,为什么在 [tView release]之后,retaincount还是1呢?这是因为 [tView release]之后, tView retaincount实际变成了0,然后tView 就被释放掉了。你后面调用tView.retainCount其实是没意义的,tView已经被释放了。所以你看到的1其实是,retainCount,retainCount2这2个变量前面被赋值的值。你如果改成赋值给一个新的变量,你就会发现是0了。而这个0其实是新的变量的初始化的值0,并不是tView.retainCount返回的0。


追问



这里release会挂掉,但是我把[tView release]写到最后面却不会挂掉。

这里该怎么管理?

不是alloc后,赋给了_view2就该立刻release的嘛?

还有,原来那个问题真的和你说得一样,在不使用self.的时候那个reatinCount真的是上面的值,release后还是上面那个值。

回答
你追问的图片里的红字理解是正确的。使用self.的作用就是在于 调用set函数去给实例变量赋值。不使用self. 直接使用_view2赋值就是等于直接给实例变量赋值,不会经过set函数。在有retain关键字的情况下,set函数里面实现了传入新参数的retain,旧参数的release。所以这样可以更好的管理传参时的内存管理。这就是为什么Apple推荐大家都用self.进行实例变量的赋值。不到万不得已的情况,不要随便直接使用_view2实例变量直接赋值。在遵循使用self.规则前提下,self.view2 = tView;语句之后 就可以立刻对[tView release]. 但是你的代码是直接使用_view2赋值的,没进过set函数,没了tView 没有retain,后面你再[tView release],其实这里tView 就已经释放了。然后你再去访问tView 的retainCount属性,必然是要crash的。 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. - (void)setView2:(UIView *)view2{  
  2.     [view2 retain];  
  3.     //view2.retainCount == 2  
  4.     [_view2 release];  
  5.     //_view2.retainCount == 0  
  6.     _view2 = view2;  
  7.     //_view2.retainCount == 2  
  8. }  

view2作为属性会自动生成setter和getter方法。self.view2 = tview;会调用上方的setter方法。

追问
那么不使用self.赋值的时候是不是不会调用上面的setter方法来retain呢?
回答
是的你可以试下  _view2 = tview;

self.会默认调用get方法,比如一个变量定义成了retain,则self.之后引用计数就会加1.strong,weak是arc的时候用到的。

官方的一种常见写法:

  1. MyClass.h 
  2. @interface MyClass NSObject 
  3.     MyObject _myObject; 
  4. @property (nonatomic, retain) MyObject *myObject; 
  5. @end 
  6. MyClass.m 
  7. @synthesize myObject _myObject; 

OK, 你现在再试下, 如果你用self._myObject = aMyObject; 或者 myObject = aMyObject; 你会得到一个错误, 为什么呢, 这里就是和Obj-c的存取方法有关了. 说白了很简单 , 大家都知道, @property (nonatomic, retain) MyObject *myObject; 是为一个属性设置存取方法, 只是平时我们用的方法名和属性名是一样的,现在你把它写成不同的名字, 就会很清楚了. _myObject是属性本身, myObject是存取方法名. 

现在我们知道self.是访问属性的存取方法了, 那存取方法又怎么工作的? self.myObject = [[MyObject alloc] init]; 为什么会有内存泄露?

get方法是:

  1. -(MyObject*)myObject{ 
  2.     return _myObject; 
  3.  

Set方法是:

  1. // assign 
  2. -(void)setMyObject:(id)newValue{ 
  3.     _myObject newValue; 
  4. // retain 
  5. -(void)setMyObject:(id)newValue{ 
  6.     if (_myObject != newValue) 
  7.         [_myObject release]; 
  8.         _myObject [newValue retain]; 
  9.      
  10. // copy 
  11. -(void)setMyObject:(id)newValue{ 
  12.     if (_myObject != newValue) 
  13.         [_myObject release]; 
  14.         _myObject [newValue copy]; 
  15.     
  16.  

其实这些方法里还有别的内容, 并不只是这些. 而且这些方法可以被重写. 比如你写一个

  1. -(MyObject*)myObject{ 
  2.     return _myObject; 

放在你的类里, 你调用self.myObject时(不要把它放在等号左边, 那会调用get方法)就会调用这个方法. 

这里多说一句, @property 是为你设置存取方法, 和你的属性无关, 你可以只写一句

  1. @property (readonly) NSString *name;  

在你的类里实现

  1. -(NSString*)name{ 
  2.     NSLog(@"name"); 
  3.     return @"MyClass"
  4.  

同样可以用self.name调用. 

顺便说一下, 如果你想在其它类访问对象属性, 而不是通过存取方法, 你可以用myClass -> myObject来访问, 这样是直接访问对象本身, 不过你先要把myObject设成@public. 但这个是官方不提倡的,


0 0
原创粉丝点击