zoukankan      html  css  js  c++  java
  • @property retain 引发的思考

    @property 官方解释:Declared Properties

    个人理解:@property的意思是自动帮添加get、set方法。
    而NSString等引用类型,需要使用retain。

    当我们不手动添加@property,如,建立一个私有变量,自己写get、set方法,通过消息发送,获取变量值。
    这里,如果此变量类型不为值类型,是否需要在set方法中,做@property的retain所做的事。

    个人觉得是需要的,即

    //H
    @property (nonatomic, retain) NSString *value;
    
    //M
    -(void)setValue:(NSString *)_value{
        if (value != _value) {
            [value release];
            value = [_value retain];
        }
    }

    但是有人觉得需要增加一步操作:

    //M
    -(void)setValue:(NSString *)_value{
        if (value) {
            if (value != _value) {
                [value release];
                value = [_value retain];
            }
        }
    }

    当原来的value值不存在,那执行[value release]不就crash了?

    理论上貌似对的,但OC中是消息机制,即发送一个消息给对象,不响应,不会做任何操作。有人说:

    NSArray *array = [[NSArray alloc] init];
    [array addObject:@"0"];

    这样就crash了。是的,这样肯定crash,因为他响应了。

    如何才不响应?当对象是nil的时候(0x00)。
    即为什么我们release一个对象后,还要让他等于nil。
    当release一个对象(A)后,该对象(A)不会立即Free,而是retainCount减1且标记内存(0x01)为可用。
    当该内存(0x01)被另一个对象(B)alloc后,该对象(A)的指针所指向的地址实际上是错误的,对A发送消息,响应了,所以crash了。(就是野指针)

    既然这样,原本if (value)完全不需要,第一次执行setValue时候,[value release]实际上执行的是:[nil release],毫无crash迹象。

    朋友说:

    -(void)setValue:(NSString *)_value{
        value = _value;
    }

    这样不就行了?是的,这是@property assign 写法,值类型,直接栈中分配,我们不需要Free。
    但,对于引用类型,这样操作应该是将value指针强行指向_value,新值赋值成功,但原指针指向的堆里的内存怎么办?
    这块只有当app close的时候,才会Free。当你的app内存占用越来越多而引发的一系列后果,你懂的!!!

    那为什么加retain?

    value = [_value retain];

    传进来的_value值可能是autorelease,或者是xxxx,保存是应该的。

    这样,那set方法应该是没问题了,我们测试下retainCount。

    -(void)setValue:(NSString *)_value{
        if (value != _value) {
            NSLog(@"%d", [value retainCount]);
            [value release];
            NSLog(@"%d", [value retainCount]);
            value = [_value retain];
            NSLog(@"%d", [value retainCount]);
        }
    }

    并执行:

    [self setValue:@"1"];
    [self setValue:@"2"];

    得到的结果是:

    2012-12-08 13:21:57.255 releaseTest[665:c07] 0
    2012-12-08 13:21:58.961 releaseTest[665:c07] 0
    2012-12-08 13:22:00.862 releaseTest[665:c07] -1
    2012-12-08 13:22:06.887 releaseTest[665:c07] -1
    2012-12-08 13:22:08.478 releaseTest[665:c07] -1
    2012-12-08 13:22:09.349 releaseTest[665:c07] -1

    执行6次,除了前2次为空,reatinCount为0外,其他4次都是有值的,居然为-1.
    为什么?

    其实:NSString为特殊,除了以[[NSString alloc] initWithFormat:@"0"]等几个特殊的方法创建的string,其他都是字符串常量,retainCount为x_MAX,是不能release的,所以大段的字符串常量内容,最好放在资源文件中进行读取。
    当你创建自己写的Class时,retainCount感觉就正常了。

    现在,set方法能用了吧?

    后续:哪错了告知下,感激不尽!!

  • 相关阅读:
    vue中使用 canvas给页面添加水印
    c++ get keyboard event
    sublime text c++ makefile
    dddd
    songwenxin
    wechat
    ddd
    log
    v3
    xiaoxiaole
  • 原文地址:https://www.cnblogs.com/maxfong/p/2808782.html
Copyright © 2011-2022 走看看