初始化属性,点符号

Mor*_*ess 20 initialization properties reference-counting objective-c dealloc

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

对于像这样的普通房产:

@property (nonatomic, retain) id foo;
Run Code Online (Sandbox Code Playgroud)

在我设置的init方法中说self.foo = nil.合成的方法首先释放或自动释放foo(不完全确定潜在的实施).被fooguaranted第一setter或getter调用之前是零?或者它会指向随机垃圾,除非我明确设置foo = nil没有点符号?

jus*_*tin 75

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

是的,这是一个坏主意.

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

2)应与它们,而在部分构造的状态(例如覆盖方法消息自initdealloc).

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

其原因是,你的目标不应该是在部分构造的状态(感兴趣的类接口的行为init...,dealloc,finalize,和许多copyWithZone:实现).你的班级应该有兴趣正确地初始化(如在init...)和清理自己,包括其成员(如dealloc),而不会引入副作用.

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

如果UseItTheRightWay真的,我们会得到结果:

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.
Run Code Online (Sandbox Code Playgroud)

如果UseItTheRightWay假的,我们会得到结果:

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............
Run Code Online (Sandbox Code Playgroud)

问题#1

这个例子的明显失败是泄漏,引入dealloc.

问题#2

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

-[MONObjectA init]
-[MONObjectB setArray:]
-[MONObjectB init]
Run Code Online (Sandbox Code Playgroud)

这是什么???之前-[MONObjectB setArray:]被称为?这意味着之前,甚至在退出之前都使用了它的实现.那不好= -[MONObjectB init]MONObjectB -[MONObjectB init]-[MONObjectA init]

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

  • 很棒的演示!直到现在才明白其含义. (3认同)