Инициализация свойства, точечная нотация - PullRequest
20 голосов
/ 09 мая 2011

Это плохая идея использовать точечную нотацию для инициализации сохранения свойств в ноль в моих методах инициализации?

С любым обычным свойством, подобным этому:

@property (nonatomic, retain) id foo;

Скажите, в моем методе инициализации я установил self.foo = nil.Синтезированный метод сначала выпускает или автоматически выпускает foo (точно не уверен в основной имплементации).Гарантируется ли foo равным нулю до первого вызова сеттера или геттера?Или это будет указывать на случайный мусор, если я явно не установлю foo = nil без точечной нотации?

1 Ответ

75 голосов
/ 09 мая 2011

Является ли плохой идеей использование точечной нотации для инициализации сохранения свойств для nil в моих методах инициализации?

Да, это плохая идея.

1) Объект уже обнулен в последовательности alloc + init, поэтому нет необходимости присваивать ему значение nil.Другими словами, этот вызов бесполезен, если только у вас нет побочных эффектов в аксессорах (на этой стадии также следует избегать побочных эффектов в аксессорах).

2) Вы должны не сообщать о себе сметоды, которые переопределяются в частично построенных состояниях (например, init и dealloc).

Есть ли причина для # 2?Я часто делаю self.array = [NSMutableArray array];в моих методах init.

Причина в том, что ваш объект не должен интересоваться поведением интерфейса класса во время частично сконструированных состояний (init..., dealloc, finalize и многие copyWithZone: реализации).Ваш класс должен быть заинтересован в правильной инициализации (как в init...) и очистке после себя, включая его членов (как в dealloc) без , не вызывающих побочных эффектов.

рассмотрим этот пример, который вы можете построить как инструмент Foundation для 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 равно верно , нам дается результат:

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 равно ложно , нам дается результат:

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]

Что это ???-[MONObjectB setArray:] называется до -[MONObjectB init]?Это означает, что реализация MONObjectB используется до -[MONObjectB init] и даже до выхода -[MONObjectA init].Это нехорошо = \

Нетривиальные проекты просто вызовут кучу нежелательных побочных эффектов, странного поведения, утечек и так далее.Сложные проекты потерпят неудачу очень очевидным и очень тонким способом, который может быть очень трудно отследить.Лучше избегать головной боли от обслуживания из-за таких тривиальных письменных различий и правильно писать классы с самого начала (даже если вы можете делать это довольно долго, без явных побочных эффектов).

...