Управление памятью iPhone (с конкретными примерами / вопросами) - PullRequest
2 голосов
/ 28 декабря 2010

Привет всем. Я знаю, что этот вопрос задавался, но у меня до сих пор нет четкой картины управления памятью в Objective-C. Я чувствую, что довольно хорошо понимаю, но я все еще хотел бы получить несколько правильных ответов для следующего кода. У меня есть ряд примеров, которые я хотел бы уточнить у кого-то (ей).

Установка значения для переменной экземпляра :

Скажем, у меня есть NSMutableArray переменная. В моем классе, когда я инициализирую его, мне нужно вызвать retain на нем?

Должен ли я сделать

fooArray = [[[NSMutableArray alloc] init] retain];

или

fooArray = [[NSMutableArray alloc] init];

Делает ли [[NSMutableArray alloc] init] уже установленный счетчик retain в 1, поэтому мне не нужно вызывать retain для него? С другой стороны, если бы я вызвал метод, который, как я знаю, возвращает объект autorelease d, мне наверняка пришлось бы вызвать retain, верно? Вот так:

fooString = [[NSString stringWithFormat:@"%d items", someInt] retain];

Свойства :

Я спрашиваю о retain, потому что я немного озадачен тем, как работает автоматический установщик @property.

Если бы я установил fooArray как @property с установленным retain, Objective-C автоматически создаст следующий установщик, верно?

- (void)setFooArray:(NSMutableArray *)anArray {
    [fooArray release];
    fooArray = [anArray retain];
}

Итак, если бы у меня был такой код: self.fooArray = [[NSMutableArray alloc] init]; (который я считаю правильным), Objective-C создает метод установки, который вызывает retain для значения, присвоенного fooArray. В этом случае значение retain будет фактически 2?

Правильный способ задания значения свойства :

Я знаю, что есть вопросы по этому и (возможно) дебатам, но как правильно установить @property?

Это

self.fooArray = [[NSMutableArray alloc] init];

Или это?

NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];

Я бы хотел получить разъяснения по этим примерам. Спасибо!

Ответы [ 3 ]

4 голосов
/ 28 декабря 2010

В соответствии с политикой Apple Object Ownership , любой метод, начинающийся со слов alloc или new или содержащий copy, принадлежит вызывающей стороне.

Чтобы получить право собственности на объект, вы должны retain его.

Таким образом, в вашем первом примере retain не требуется, поскольку вы уже владеете объектом.

Правильный способ сделать это:

fooArray = [[NSMutableArray alloc] init];

Поскольку autoreleased объекты принадлежат текущему пулу автоматического выпуска, вы должны вызвать retain для них, чтобы получить право собственности на них, поэтому этот пример верен:

fooString = [[NSString stringWithFormat:@"%d items", someInt] retain];

Это также будет нормально работать:

self.fooString = [NSString stringWithFormat:@"%d items", someInt]; //retained by property setter

И для вашего последнего примера использования установщика свойств это будет правильный способ сделать это:

NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];

Вместо того, чтобы делать вышеупомянутое, я бы предложил следующее решение:

self.fooArray = [NSMutableArray arrayWithCapacity:10];

arrayWithCapacity: вернет автоматически освобожденный NSMutableArray, то есть retain -edметод установки свойств.:)

3 голосов
/ 28 декабря 2010

В идеале вы хотели бы использовать средства доступа, когда это возможно, особенно при работе с объектами, поскольку они помогают избежать многих проблем с памятью. Так что даже для переменных экземпляра вы должны сделать:

self.fooArray = ...;

вместо

fooArray = ...;

Причина, по которой вы должны объявлять свойства для переменных экземпляра объекта, заключается в том, что управление памятью немного сложнее, и воссоздание его вручную каждый раз сложно. Правильный установщик для неатомического сохраненного свойства будет выглядеть следующим образом:

- (void)setFoo:(NSArray *)aFoo {
    if (foo == aFoo) {
        return;
    }
    NSArray *oldFoo = foo;
    foo = [aFoo retain];
    [oldFoo release];
}

Вы правы в том, что переменная экземпляра имеет счет сохранения 2, когда вы делаете что-то вроде этого (при условии, что foo сохраняется):

self.foo = [[NSMutableArray alloc] init];

Первый счет отсчета поступает от alloc, а второй от вашего синтезированного сеттера. Любой из них должен работать:

// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];

// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];

// an even shorter version of the above
self.foo = [NSMutableArray array];

Чтобы создать частные свойства, вы можете объявить их как расширение класса в файле реализации .m. В качестве примера рассмотрим простой объект Person с именем и логическим свойством didSave, которое просто указывает, был ли объект сохранен в какой-либо базе данных или нет. Поскольку мы не хотим показывать это внешнему миру, но сохраняем преимущества свойств внутри файла реализации, мы можем создать заголовочный файл со всеми переменными экземпляра (public, private, protected) и только с общими свойствами:

// Person.h

@interface Person {
    NSString *name;

    @private
    BOOL didSave;
}

@property (nonatomic, retain) NSString *name;

@end

Но объявите частные свойства внутри реализации:

// Person.m

// property is declared as a class extension, making it 
// invisible to the outside world.
@interface Person ()
    @property BOOL didSave;
@end

@implementation

// synthesize as normal
@synthesize name, didSave;

@end
0 голосов
/ 28 декабря 2010

Прежде всего, с этой строкой:

fooArray = [[NSMutableArray alloc] init];

fooArray автоматически будет иметь счет сохранения 1.

Во-вторых, да, это 2. И ваше предположение о реализации сеттераявляется правильным.

В-третьих, последний является правильным

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...