黑马程序员技术交流社区

标题: 关于在dealloc里面设置sefl = nil [打印本页]

作者: 汪坤洋    时间: 2015-11-9 00:41
标题: 关于在dealloc里面设置sefl = nil
今天一个同学问我一个问题,感觉很有意思,分享出来给大家,也感谢这位同学让我学到不少东西
问题的主要点就是 在dealloc里面设置sefl = nil
main 函数
Car *car1 = [Car new];
        car1.speed = 280;
        car1.name = @"君越";
        
        [fengjie setCar:car1];
        NSLog(@"%lu",[car1 retainCount]);
        
        
        Car * car2 = [Car new];
        car2.speed = 350;
        car2.name = @"宝马";
        
        [fengjie setCar:car2];
        [fengjie goLasa];
        NSLog(@"%lu",[car1 retainCount]);
        NSLog(@"%@",car1);
        [car1 release];
        //[car1 release];
        NSLog(@"%@",car1);
        //car1 = nil;//在这边调用car1赋值为nil能成功是因为car1是栈区里的变量,而堆区的对象已经释放了。下面35行重新设置[fengjie setCar:car1]就不行了。但是在car自己的dealloc里面设置sefl = nil;却能重新调用car堆内的对象,为什么?而且僵尸对象检测不到car1。
        
        
        /*
           
         在car自己的dealloc里面设置sefl = nil
         
         使释放内存的方法失效了  如果你在 [super dealloc]  后面写就会报僵尸对象  或者重新调用一下[super dealloc] 方法也会报僵尸对象
         
         这个问题最根本的原因有两点
         1、self存在作用域   出了dealloc方法后又会重新指向对象
         2、对象释放 其实是在父类方法里面执行的
         
         
         关于self作用域问题 在对象方法中self 就是一个对象 但是其本质应该是一个指针 谁调用的 就指向谁   一个存储对象地址的指针 把self=nil只是把这个指针指向了空  但是不会影响我们在外面创建的对象
         
         以后千万不要在dealloc方法里面写   sefl = nil
         
         */
        //释放失败,在这里继续调用也会成功
        [car1 ssss];
        //NSLog(@"%@",car1);
        
        
        
        
        //[car1 release];
        NSLog(@"%lu",[car1 retainCount]);
        [fengjie setCar:car1];
        //[fengjie release];
        [fengjie goLasa];
        [fengjie goLasa];

car代码
- (void) dealloc {
    NSLog(@"1----%@",self);
    self = nil;   //这样写会造成内存泄漏
    NSLog(@"2----%@",self);
    //释放对象内存应该写在父类的方法中 提前把self指向空  父类释放对象就会失败  self 应该也是有作用域的
    [super dealloc];
}

-(void)ssss{
    NSLog(@"3----%@",self);
    [super dealloc];
}
作者: 汪坤洋    时间: 2015-11-9 00:44
以上是主要代码,不太会编辑,大家将就看吧
作者: 向日葵的微笑    时间: 2015-11-9 00:46
赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞
作者: wx_xO9vSwPo    时间: 2015-11-9 01:09
牛,赞赞赞赞
作者: 许本亮    时间: 2015-11-9 08:55
受教了,顶一下
作者: Windnon    时间: 2015-11-9 22:09
不明觉厉~~~~~~~~~~~~
作者: liuch111    时间: 2015-11-9 23:16
还好我看过 xcode版 源码...  不然 "大神" 贴出来的代码能把人看晕

  不过还是谢谢分享,,  
作者: 汪坤洋    时间: 2015-11-10 15:15
整理之后的
问题
        在car自己的dealloc里面设置sefl = nil。

解决过程:

主要的类和分析见下面
main方法

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *fengjie = [Person new];
        Car *car1 = [Car new];
        car1.speed = 280;
        car1.name = @"君越";
        
        [fengjie setCar:car1];//这时候car1 计数器为2
        
        NSLog(@"%lu",[car1 retainCount]);
        
        [car1 release];//这时候car1 计数器为1
        NSLog(@"%lu",[car1 retainCount]);
                
        [car1 release];//这时候car1 计数器为0  调用dealloc方法(方法见car.m文件)
        
        
        NSLog(@"%lu",[car1 retainCount]);//正常结果应该报僵尸错误 但是在 dealloc里面设置sefl = nil  使对象释放失败 这时候返回计数器为 1
        
        //在发下一条消息前  self是指向nil的
        Car *susu = [car1 self];
        
        [car1 release];//继续 release  但是这时候对象不会继续自动调用 dealloc 但是计数器返回的数字很奇怪
        NSLog(@"%lu",[car1 retainCount]);// 返回  4611686018427387904
        NSLog(@"%d",[car1 retainCount]);// 返回 0
        
        //如果重新调用父类的dealloc方法 对象还是可以被释放的 说明释放对象的方法是写在nsobject的dealloc方法里
        //[car1 ssss];
        //这时候car1 被释放了 继续调用就会报错
        
        //NSLog(@"%@",car1);
        
        [fengjie release];
        
        /*
         
         这个问题最根本的原因有两点
            1、self存在作用域   出了dealloc方法后又会重新指向对象(针对这点 后面有详细解释)
            2、对象释放 其实是在父类方法里面执行的
         
         结论
            以后千万不要在dealloc方法里面写   sefl = nil   这样会造成内存泄漏
         
         引发的其他问题
            释放失败之后的计数器 结果是1   当再次 release后  计数器的结果在%lu上是一个很大的数字 在%d中是0
            self究竟是什么,详情请见《oc加强2》
         */
        
    }
    return 0;
}



Car.m


#import "Car.h"


@implementation Car



- (void)run{
    NSLog(@"%@以%d的速度向前奔跑",_name,_speed);
}

- (void) dealloc {
    NSLog(@"1----%p",&self);
    self = nil;   //这样写会造成内存泄漏
    NSLog(@"2----%p",&self);
    //释放对象内存应该写在父类的方法中 提前把self指向空  父类释放对象就会失败  self 应该也是有作用域的
    [super dealloc];
}

-(void)ssss{
    NSLog(@"3----%@",self);
    [super dealloc];
}

@end



结论
        以后千万不要在dealloc方法里面写   sefl = nil   这样会造成内存泄漏  也不要漏写[super dealloc]正真释放内存的方法就在这里
       
引发的其他问题
        释放失败之后的计数器 结果是1   当再次 release后  计数器的结果是一个很大的数字
        self究竟是什么,详情请见《oc加强2》




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2