Главная » iPhone, Objective-C, Программирование для iOS и MacOS » Создание класса Asset Objective-C

0

Создайте новый файл для субкласса NSObject. Присвойте ему имя Asset. Откройте файл Asset.h, объявите две переменные экземпляров и два свойства:

#import <Foundation/Foundation.h>

@interface Asset : NSObject

{

NSString *label;  unsigned int resaleValue;

}

@property (strong) NSString *label;

@property unsigned int resaleValue;

@end

Обратите внимание на модификатор strong у объявления @рrореrtу для label. Он означает: «Это указатель на объект, владельцем которого я становлюсь». (Другие возможные значения этого атрибута рассматриваются в главе 20.)

Напомню, что объект, у которого нет ни одного владельца, уничтожается. При

уничтожении объекту отправляется сообщению dealloc. (Все объекты наследуют метод dealloc от NSObject.) Переопределение метода dealloc позволит нам понаблюдать за уничтожением экземпляров Asset.

Чтобы было понятно, какой именно экземпляр Asset уничтожается, также необходимо реализовать другой метод NSObject, который называется description. Метод возвращает строку с содержательным описанием экземпляра класса. Для экземпляров Asset метод description будет возвращать строку, включающую значения label и resaleValue текущего экземпляра.

Откройте файл Asset.m. Синтезируйте методы доступа для переменных экземпляров, а затем переопределите description и dealloc.

#import "Asset.h"

@implementation Asset

@synthesize label, resaleValue;

-­‐   (NSString  *)description

{

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

}

-­‐    (void)dealloc

{

}

@end

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

Обратите внимание на заполнитель %@в форматных строках приведенного выше кода. Этот заполнитель заменяется результатом отправки сообщения соответствующей переменной (которая должна содержать указатель на объект, получающий  сообщение).

Попробуйте построить программу. чтобы посмотреть, не были ли допущены

ошибки при вводе. Программу можно построить и без запуска – для этой цели используется комбинация клавиш Command+B. Данная возможность может быть полезна для проверки кода без запуска программы – например, если вы знаете, что программа к запуску еще не готова.

Также всегда рекомендуется строить программу после внесения изменений,

чтобы любые синтаксические ошибки обнаруживались и исправлялись немедленно. Потом будет неочевидно, какие изменения отвечают за появление «новой» ошибки.

Добавление отношения «один ко многим» В Employee

А сейчас мы добавим в класс Employee отношение «один ко многим». Напомню, что в этом отношении задействован объект коллекции (например, массива) и объекты, содержащиеся в коллекции.

Два  важных  факта,  которые  необходимо  знать  о  коллекциях  и  владельцах

объектов:

•  При добавлении объекта коллекция сохраняет указатель на объект, и у объекта появляется  владелец.

•  При удалении объекта коллекция освобождает указатель на объект, а у объекта теряется владелец.

Чтобы реализовать отношение «один ко многим». В Employee, нам понадобится новая переменная экземпляра, в которой будет храниться указатель на изменяемый массив ресурсов. Также понадобится пара дополнительных методов. Откройте файл Employee.h и добавьте их:

#import "Person.h"

@class Asset;

@interface Employee : Person

{

int employeeID;

NSMutableArray *assets;

}

@property int employeeID;

-­‐   (void)addAssetsObject:(Asset  *)a;  -­‐   (unsigned  int)valueOfAssets;

@end

Обратите внимание на строку @class Asset;. В процессе чтения файла компилятор встречает имя класса Asset. Если у него нет никакой информации об этом классе, то компилятор выдает ошибку. Строка @class Asset; сообщает компилятору:

«Класс с именем Asset существует. Если он встретится в этом файле – без паники. И это все, что тебе пока необходимо знать».

Использование  @class вместо  #import предоставляет  компилятору  меньше

информации, но ускоряет обработку этого конкретного файла. Мы можем использовать директиву @сlаss в Employee.h и других заголовочных файлах, потому что для обработки файла с объявлениями компилятору не требуется много информации.

Теперь обратимся к файлу Employee.m. В отношениях типа «один ко многим».

необходимо создать объект коллекции (массив в нашем случае), прежде чем что-либо сохранять в нем. Это можно сделать при создании исходного объекта (экземпляр Employee) или же не торопиться и подождать первой операции с коллекцией. В нашей программе будет использован второй вариант.

#import "Employee.h"

#import "Asset.h"

@implementation Employee

@synthesize employeeID;

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

{

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

// Create the array

assets = [[NSMutableArray alloc] init];

}

[assets addObject:a];

}

-­‐    (unsigned  int)valueOfAssets

{

// Sum up the resale value of the assets unsigned int sum = 0;

for (Asset *a in assets) { sum += [a resaleValue];

}

return sum;

}

-­‐      (float)bodyMassIndex

{

float normalBMI = [super bodyMassIndex]; return normalBMI * 0.9;

}

-­‐   (NSString  *)description

{

return [NSString stringWithFormat:@"<Employee %d: $%d in assets>", [self employeeID], [self valueOfAssets]];

}

-­‐    (void)dealloc

{

}

@end

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

Для   обработки   файла   Employee.m   компилятору   необходима   подробная информация о классе Аsset, поэтому мы импортируем Asset.h вместо использования

@сlаss.

Также  обратите  внимание  на  переопределение  description и  dealloc для отслеживания удаления экземпляров Employee.

Постройте проект и убедитесь, что он не содержит ошибок.

Теперь необходимо создать объекты ресурсов и закрепить их за работниками. Отредактируйте файл main.m:

#import <Foundation/Foundation.h> #import "Employee.h"

#import "Asset.h"

int main(int argc, const char * argv[])

{

@autoreleasepool {

// создание массива объектов Employee

NSMutableArray *employees = [[NSMutableArray alloc] init]; for (int i = 0; i < 10; i++) {

// создание экземпляра Employee

Employee *person = [[Employee alloc] init];

// присваивание значений переменным экземпляра [person setWeightInKilos:90 + i];

[person  setHeightInMeters:1.8  -­‐   i/10.0]; [person   setEmployeeID:i];

// включение экземпляра в массив employees [employees addObject:person];

}

// создание 10 экземпляров assets for (int i = 0; i < 10; i++) {

// создание экземпляра asset

Asset *asset = [[Asset alloc] init];

// присваивание метки

NSString *currentLabel = [NSString stringWithFormat:@"Laptop %d", i]; [asset setLabel:currentLabel];

[asset setResaleValue:i * 17];

// получение случайного числа от 0 до 9 включительно NSUInteger randomIndex = random() % [employees count];

// получение соответствующего работника

Employee *randomEmployee = [employees objectAtIndex:randomIndex];

// назначение ресурса работнику

[randomEmployee addAssetsObject:asset];

}

NSLog(@"Employees: %@", employees); NSLog(@"Giving up ownership of one employee"); [employees removeObjectAtIndex:5]; NSLog(@"Giving up ownership of array"); employees = nil;

}

return 0;

}

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

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 deallocating <Employee 5: $136 in assets> deallocating <Laptop 3: $51 > deallocating <Laptop 5: $85 >

Giving up ownership of array  deallocating <Employee 0: $0 in assets> deallocating <Employee 1: $153 in assets> deallocating <Laptop 9: $153 >

deallocating <Employee 9: $136 in assets> deallocing <Laptop 8: $136 >

При удалении из массива экземпляра Employee с номером 5 экземпляр уничтожается, потому что у него не остается владельцев. После этого уничтожаются его ресурсы, потому что у них тоже не осталось владельцев. (Поверьте на слово: метки, то есть экземпляры NSString, уничтоженных ресурсов тоже будут уничтожены, потому что у них тоже не остается владельцев.)

Когда  employees задается  значение  nil,  у  массива  не  остается  владельца.

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

Удобно, правда? Как только объект становится ненужным, он уничтожается.

Если ненужные объекты почему-либо не уничтожаются, говорят, что в программе возникает утечка памяти. Объекты задерживаются в памяти сверх положенного времени, приложение начинает поглощать все больше и больше памяти. B iOS операционная система в конечном итоге аварийно завершает приложение. В Мас OS Х

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

Упражнение

Используя класс StockHolding из предыдущего упражнения, напишите программу, которая создает экземпляр класса Portfolio (портфель акций) И заполняет его объектами StockHolding из упражнения предыдущей главы. Объект Portfolio должен уметь вычислять свою текущую стоимость.

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

По теме:

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