zoukankan      html  css  js  c++  java
  • Objective-C 【在手动内存管理中如何写set方法】

    ———————————————————————————————————————————
    set方法的内存管理

    代码:

    #import <Foundation/Foundation.h>

    @interface Car : NSObject
    -(void)run;
    @property int speed;
    @end

    @implementation Car
    -(void)run
    {
        NSLog(@"car run!");
    }
    - (void)dealloc
    {
        NSLog(@"car dealloc!");
        [super dealloc];
    }
    @end

    @interface Person : NSObject
    {
        Car *_car;
    }
    -(void)driver;
    -(void)setCar:(Car *)car;
    @end

    @implementation Person

    //test1中运用到的set方法
    //-(void)setCar:(Car *)car
    //{
    //   [_car release];//release一下原来的内存(注意:如果是第一次调用set方法,_car里面是nil,nil!=car,不过此时也是可以调用[_car release];的,只是不起作用罢了~)
    //    _car=[car retain];//给car的计数+1,然后赋给_car(如果是第一次set,那么为什么这里要retain呢,因为必须让计数等于2,因为在main函数里,我们在[p release]; 和 [car release];各释放了一次car,所以-2的前提是要+2)
    //}

    //改进后的set方法
    -(void)setCar:(Car *)car
    {
    //    如果 _car 和 car 相等,那么就无需做任何操作了,因为之前已经做过一次setCar了。如果对原值操作release和retain。那么就会出现野指针(“僵尸对象复活”)。所以只有传入的值和先前的值不一样,才会做下列操作:①release原值 ②_car=car; ③retain新值
        if (_car!=car) {
            [_car release];
            _car=[car retain];
        }
    }
    -(void)driver
    {
        [_car run];
    }
    - (void)dealloc
    {
        [_car release];//上节知识点,我们之前在setCar里面retain car了一次,所以必须让car的计数减1.所以要再Person里有Car的实例变量,若要释放car的内存,在Person的dealloc里面可以做到这一点。但是我们就没法在Car的dealloc里面释放Person了。
        NSLog(@"person dealloc!");
        [super dealloc];
    }
    @end

    //在test1中暂时保存~需要时拿出来运行检验
    void test1()
    {
        //        set方法的内存管理(1)———— 原对象无法被释放造成的内存泄漏问题
        
        //        创建Person的实例对象p
        Person *p=[[Person alloc]init];//p   1
        //        创建Car的实例对象car1
        Car *car1=[[Car alloc]init];//car1   1
        car1.speed=120;
        
        //        将car1赋给p(p拥有了第一辆车car1)
        [p setCar:car1];//car1   2(在set方法中retain了一下)
        
        [p driver];//想要driver,就要给p的Car赋值~(你要先给他一辆车)
        
        [car1 release];//car1用完了我们可以将car1释放掉,car1   1
        
        //        创建Car的实例对象car2
        Car *car2=[[Car alloc]init];//car2   1
        
        //        将car2赋给p(p拥有的第二辆车car2)
        [p setCar:car2];//car2   2
        //         我们知道,在setCar中是这么一句话:_car=[car retain];  在此处,没运行这句话之时,因为之前曾经调用的setCar,所以_car中存的是car1的内存地址。而运行到此处_car又变为了新的car2,car2变成了2,而car1还是1没变。
        
        [car2 release];//car2   1
        
        [p release];//p   0      car2   0     car1   1
        //        这样看来,因为_car中的内存地址在两次setCar中发生了改变,导致本来意图在[p release]的同时想要[car1 release],却[car2 release]
        //        这样导致car1的内存没有释放完毕,所以导致的内存泄漏,那么我们就应该在setCar 传入第二个值的时候先将第一个值释放(也就是此时_car中保存的地址release掉,这样就不会造成car1的内存泄漏)

    }

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            //        set方法的内存管理(2)———— 同一个实例变量set两次,出现野指针(“僵尸对象复活”)
            
            Person *p2=[[Person alloc]init];//p2   1
            
            Car *car3=[[Car alloc]init];//car3   1
            
            [p2 setCar:car3];//car3   2   (_car里面目前存的是car3的地址)
            
            [p2 driver];
            
            [p2 setCar:car3];//如果说setCar对同一个实例变量进行操作,也就是将car3 setCar了两次,那样的话car3   3 ,那样的话必然会造成car3的内存泄漏,所以说我们有必要进行一个if语句的判断,也就是如果传进来的参数地址和_car中的地址一致,那么就没有必要进行retain了。于是我们可以改进一下set方法。
            
            [car3 release];
            
            [p2 release];
            
         /*
            set方法的内存管理(3)———— set的写法(在手动管理内存的情况下)
            
             (1)基本数据类型
             
             -(void)setSpeed:(int)speed
             {
                _speed=speed;
             }
             
             
             (2))OC对象
             
             -(void)setCar:(Car *)car
             {
                //①先判断_car和car表示的地址是否一致(也就是先看car是不是新传来的对象)
                if(_car!=car)
                {
                    //②对旧对象做一次release
                    [_car release];
                    //③对新对象做一次retain
                    _car=[car retain];
                }
             }
             
             */
        }
        return 0;
    }

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    DES算法实现
    2018-2019-2 20175226 实验五《网络编程与安全》实验报告
    2018-2019-2 20175226王鹏雲 实验四《Android程序设计》实验报告
    第05组 Beta冲刺(1/4)
    Alpha事后诸葛亮
    第05组 Alpha冲刺(4/4)
    第05组 Alpha冲刺(3/4)
    第05组 Alpha冲刺(2/4)
    第05组 Alpha冲刺(1/4)
    第05组 团队Git现场编程实战
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787883.html
Copyright © 2011-2022 走看看