Главная » iPhone, Objective-C, Программирование для iOS и MacOS » Предотвращение утечки памяти Objective-C

0

В программировании часто встречаются двусторонние отношения. Допустим, объект ресурса должен иметь возможность узнать, за кем из работников он закреплен. Давайте включим это отношение в нашу программу. Новая диаграмма объектов будет выглядеть как на рис. 20.1.

Рис. 20.1. Добавление отношения

С точки зрения архитектуры эта связь реализуется добавлением указателя от потомка (экземпляр Asset) к родителю (экземпляр Employee).

Добавьте в Asset.h переменную экземпляра для хранения указателя на объект работника:

#import <Foundation/Foundation.h>

@class Employee;

@interface Asset : NSObject

{

NSString *label;  Employee *holder; unsigned int resaleValue;

}

@property (strong) NSString *label;

@property (strong) Employee *holder;

@property unsigned int resaleValue;

@end

В   файле   Asset.m   сгенерируйте   методы       доступа   и   расширьте   метод

description, чтобы он выводил информацию о держателе ресурса:

#import "Asset.h"

#import "Employee.h"

@implementation Asset

@synthesize label, resaleValue, holder;

-­‐   (NSString  *)description

{

// держатель ресурса отличен от nil? if ([self holder]) {

return [NSString stringWithFormat:@"<%@: $%d, assigned to %@>", [self label], [self resaleValue], [self holder]];

} else {

return [NSString stringWithFormat:@"<%@: $%d unassigned>", [self label], [self resaleValue]];

}

}

-­‐    (void)dealloc

{

}

@end

NSLog(@"deallocing %@", self);

Возникает важный вопрос: как при совместном использовании классов Asset и Employee обеспечить согласованность двух отношений? Иначе говоря, ресурс должен присутствовать в массиве ресурсов работника в том и только в том случае, если работник является держателем ресурса. Возможны три варианта:

•  Явно задать оба отношения:

[vicePresident addAssetsObject:townCar]; [townCar setHolder:vicePresident];

•  В методе, задающем значение указателя потомка, добавить потомка в коллекцию родителя:

-­‐    (void)setHolder:(Employee   *)e

{

holder = e;

[e addAssetsObject:self];

}

Такое решение применяется относительно редко.

•  В методе, добавляюшем потомка в коллекцию родителя, задать указатель потомка.

В этом упражнении мы воспользуемся последним вариантом. В файле Employee.m расширьте метод addAssetsObject:, значение чтобы он также присваивал holder:

-­‐    (void)addAssetsObject:(Asset   *)a

{

// Is assets nil? if (!assets) {

// Create the array

assets = [[NSMutableArray alloc] init];

}

[assets addObject:a];

[a setHolder:self];

}

(Одна из моих любимых ошибок: два метода доступа автоматически вызывают

друг друга. В программе возникает бесконечный цикл: addAssetsObject: вызывает setHolder:, который вызывает addAssetsObject:, который вызывает setHolder:, который…)

Постройте и запустите программу. Результат должен выглядеть примерно так:

Employees: (

"<Employee 0: $0 in assets>", "<Employee 1: $153 in assets>", "<Employee 2: $119 in assets>", "<Employee 3: $68 in assets>", "<Employee 4: $0 in assets>", "<Employee 5: $136 in assets>", "<Employee 6: $119 in assets>", "<Employee 7: $34 in assets>", "<Employee 8: $0 in assets>", "<Employee 9: $136 in assets>"

)

Giving up ownership of one employee Giving up ownership of array deallocating <Employee 0: $0 in assets> deallocating <Employee 4: $0 in assets> deallocating <Employee 8: $0 in assets>

Обратите внимание: ни один из объектов работников, которым назначены ресурсы, не уничтожается. То же происходит и с ресурсами. Почему?

Источник: Аарон Хилегас, «Objective-C. Программирование для iOS и MacOS», 2012 г.

По теме:

  • Комментарии