ios何时使用self.

从内存管理来说明使用self.和不使用self的区别:
ViewController.h文件,使用Student类,代码如下:
#import <UIKit/UIKit.h>
@class Student;

@interface ViewController : UIViewController{
      
       Student *_student;
}
 
@property (nonatomic, retain) Student *student;

@end
ViewController.m文件,代码:
#import "ViewController.h"
#import "Student.h"

@implementation ViewController
@synthesize student = _student;
   
- (void)didReceiveMemoryWarning
{
  [super didReceiveMemoryWarning];
}
    
#pragma mark - View lifecycle
  
- (void)viewDidLoad
{
 [super viewDidLoad];
}
 
- (void) dealloc
{
 [_student release];
 _student = nil;
 [super dealloc];
}
其它的方法没有使用到,所以这里就不在显示了。
在ViewController.m的viewDidLoad方法中创建一个Student类的对象
  Student *mystudent = [[Student alloc] init];
  self.student = mystudent;
  [mystudent release];
这是相信有人会有疑问了,问什么创建student对象要这么复杂,似乎直接使用self.student = [[Student alloc] init]; 也没有问题,不加self有时也是挺正常的呀?
接下来就需要从内存角度来分析它们之间的区别了:
1、加self的方式:
Student *mystudent = [[Student alloc] init];       //mystudent 对象 retainCount = 1;
self.student = mystudent;   //student 对象 retainCount = 2;
[mystudent release];  //student 对象 retainCount = 1;

//student的property 是retain 默认使用self.student引用计数+1。


2、不加self的方式
Student *mystudent = [[Student alloc] init];       //mystudent 对象 retainCount = 1;
student = mystudent;   //student 对象 retainCount = 1;
[mystudent release];   //student 对象内存已释放,如果调用,会有异常

3、加self直接赋值方式
self.student = [[Student alloc] init];  //student 对象 retainCount = 2;容易造成内存泄露
由于objective-c内存管理是根据引用计数处理的,当一个对象的引用计数为零时,gcc才会释放该内存。
转载:http://jordy.easymorse.com/?p=805
 
个人总结:只需要在属性初始化的时候使用self.属性,其他时候直接使用属性名就行;使用self.是 使retaincount+1,为了确保当前类对此属性具有拥有权
个人使用习惯:
@interface CustomClass : UIViewController
{
    NSString *str
}
@property (retain, nonatomic) NSString *str;


@implementation CustomClass
@synthesize str;

-(void)viewDidLoad
{
    //方法一  用alloc必须手动释放一次
    self.str  =  [[NSString alloc]initWithString:@"my str"];
     [str release];
    //方法二 用类方法不用
   self.str =     [NSString stringWithString:@"my str"];

    以后调用时直接使用str,不必使用self.str
   [str appendString:@"\n"];
}


//在dealloc中必须释放
- (void)dealloc
{
    //方法一
    [str release];
    str = nil;
    //方法二
    self.str = nil;

    [super dealloc];
}        

看图:

.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方法是:

-(MyObject*)myObject{ 
    return _myObject; 
} 

Set方法是:
// assign 
-(void)setMyObject:(id)newValue{ 
    _myObject = newValue; 
} 
// retain 
-(void)setMyObject:(id)newValue{ 
    if (_myObject != newValue) { // 若先前已经赋予相同的值,则不会引起计数器变化
        [_myObject release];
        _myObject = [newValue retain]; // newValue的计数器值为1,再次retain后变为2,所以self.计数器会加1 
    }  
} 
// copy 
-(void)setMyObject:(id)newValue{ 
    if (_myObject != newValue) { // 同上
        [_myObject release]; 
        _myObject = [newValue copy]; // 同上
    } 
} 

retain关键字的作用是,在实现set函数内部,retain当前变量,具体实现是这样:
-(void)setView2:(UIView*)view{
   [_view2 release];
   _view2 = [view retain];
}

而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的。 

- (void)setView2:(UIView *)view2{
    [view2 retain];
    //view2.retainCount == 2
    [_view2 release];
    //_view2.retainCount == 0
    _view2 = view2;
    //_view2.retainCount == 2
}

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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值