初始化属性,点符号

时间:2011-05-09 04:55:35

标签: objective-c initialization properties dealloc reference-counting

使用点表示法在我的init方法中将retain属性初始化为nil是不是一个坏主意?

对于这样的普通财产:

@property (nonatomic, retain) id foo;

在我的init方法中说我设置了self.foo = nil。合成的方法首先释放或自动释放foo(不完全确定底层的实施)。 foo在第一个二传手或下注之前是否保证为零?或者它会指向随机垃圾,除非我明确设置foo = nil没有点符号?

1 个答案:

答案 0 :(得分:75)

  

在我的init方法中使用点表示法将retain属性初始化为nil是不是一个坏主意?

是的,这是一个坏主意。

1)对象已在alloc + init序列中归零,因此无需将其指定为nil。换句话说,除非你的访问者有副作用,否则这个调用是无用的(在这个阶段也应该避免访问者的副作用)。

2)你应该使用在部分构建状态下被覆盖的方法消息自我(例如initdealloc)。

  

#2有原因吗?我经常做self.array = [NSMutableArray array];在我的init方法中。

原因是你的对象不应该对部分构造状态(init...deallocfinalize和许多copyWithZone:实现中的类接口的行为感兴趣。您的班级应该有兴趣正确初始化(如init...)并清理其自身,包括其成员(如dealloc,而不介绍副作用。

考虑这个例子,您可以将其构建为OS X的基础工具:

#import <Foundation/Foundation.h>

enum { UseItTheRightWay = true -OR- false };

@interface MONObjectA : NSObject
{
    NSMutableArray * array;
}

@property (nonatomic, retain) NSArray * array;

@end

@implementation MONObjectA

@synthesize array;

- (id)init
{
    self = [super init];
    if (0 != self) {
        NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
        if (UseItTheRightWay) {
            array = [NSMutableArray new];
        }
        else {
            self.array = [NSMutableArray array];
        }
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
    if (UseItTheRightWay) {
        [array release], array = nil;
    }
    else {
        self.array = nil;
    }
    [super dealloc];
}

@end

@interface MONObjectB : MONObjectA
{
    NSMutableSet * set;
}

@end

@implementation MONObjectB

- (id)init
{
    self = [super init];
    if (0 != self) {
        NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
        set = [NSMutableSet new];
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
    [set release], set = nil;
    [super dealloc];
}

- (void)setArray:(NSArray *)arg
{
    NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
    NSMutableSet * tmp = arg ? [[NSMutableSet alloc] initWithArray:arg] : nil;
    [super setArray:arg];
    [set release];
    set = tmp;
}

@end

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    [[MONObjectB new] release];

    /* the tool must be named 'Props' for this to work as expected, or you can just change 'Props' to the executable's name */
    system("leaks Props");

    [pool drain];
    return 0;
}

此测试中切换行为的主要开关是UseItTheRightWay

如果UseItTheRightWay true ,我们会得到结果:

2011-05-09 01:52:11.175 Props[45138:a0f] -[MONObjectA init], <MONObjectB: 0x10010c750>
2011-05-09 01:52:11.177 Props[45138:a0f] -[MONObjectB init], <MONObjectB: 0x10010c750>
2011-05-09 01:52:11.179 Props[45138:a0f] -[MONObjectB dealloc], <MONObjectB: 0x10010c750>
2011-05-09 01:52:11.179 Props[45138:a0f] -[MONObjectA dealloc], <MONObjectB: 0x10010c750>
leaks Report Version:  2.0
Process:         Props [45138]
< --- snip --- >        
Process 45138: 1581 nodes malloced for 296 KB
Process 45138: 0 leaks for 0 total leaked bytes.

如果UseItTheRightWay false ,我们会得到结果:

2011-05-09 01:55:51.611 Props[45206:a0f] -[MONObjectA init], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.614 Props[45206:a0f] -[MONObjectB setArray:], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.615 Props[45206:a0f] -[MONObjectB init], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.617 Props[45206:a0f] -[MONObjectB dealloc], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.618 Props[45206:a0f] -[MONObjectA dealloc], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.618 Props[45206:a0f] -[MONObjectB setArray:], <MONObjectB: 0x10010c750>
leaks Report Version:  2.0
Process:         Props [45206]
 < --- snip --- >    
Process 45206: 1585 nodes malloced for 297 KB
Process 45206: 1 leak for 48 total leaked bytes.
Leak: 0x100110970  size=48  zone: DefaultMallocZone_0x100005000 instance of 'NSCFSet', type ObjC, implemented in Foundation 
    0x70294ff8 0x00007fff 0x00001080 0x00000001     .O)p............
    0x00000001 0x00000000 0x00000000 0x00010000     ................
    0x707612a8 0x00007fff 0x00000000 0x00000000     ..vp............

问题#1

这个例子的明显失败是dealloc中引入的泄漏。

问题#2

咬你的第二件事是微妙的:

-[MONObjectA init]
-[MONObjectB setArray:]
-[MONObjectB init]

这是什么???在{/ em> -[MONObjectB setArray:]之前,-[MONObjectB init]被称为?这意味着MONObjectB的实现在 -[MONObjectB init]之前使用,甚至在-[MONObjectA init]退出之前。这不好= \

非平凡的设计只会产生一系列不良副作用,奇怪的行为,泄漏等等。复杂的设计将以非常明显,非常微妙的方式失败,这些方式很难追踪。最好避免因这些微不足道的书面差异引起的维护问题,并从一开始就以正确的方式编写课程(即使你可以在很长一段时间内完成这项工作,没有明显的副作用)。