Читать книгу iOS. Приемы программирования - Вандад Нахавандипур - Страница 15

Глава 1. Реализация контроллеров и видов
1.0. Введение
Добавление нового функционала к классам с помощью методов

Оглавление

Методы – это строительные блоки, из которых состоят классы. Например, класс Person может иметь логические возможности – обозначим их как «ходить», «дышать», «есть» и «пить». Обычно такие функции инкапсулируются в методах.

Метод может принимать параметры. Параметры – это переменные, передаваемые вызывающей стороной при вызове метода и видимые только этому методу. Например, в упрощенном мире у нашего класса Person был бы метод walk. Но вы могли бы добавить к этому методу параметр или аргумент и назвать его walkingSpeed. Этому параметру вы бы присвоили тип CGFloat. Теперь, если другой программист вызовет этот метод в вашем классе, он может указать, с какой скоростью будет идти Person. Вы как автор класса напишете соответствующий код, который будет обрабатывать различные скорости ходьбы Person. Не переживайте, если у вас возникает ощущение «как-то много работы получается». Рассмотрим следующий пример. В нем я добавил метод в файл реализации того класса Person, который мы создали в подразделе «Как создавать классы и правильно пользоваться ими» данного раздела.


#import "Person.h"


@implementation Person


– (void) walkAtKilometersPerHour:(CGFloat)paramSpeedKilometersPerHour{

/* здесь пишем код для этого метода */

}


– (void) runAt10KilometersPerHour{

/* Вызываем метод walk в нашем собственном классе и передаем значение 10 */

[self walkAtKilometersPerHour:10.0f];

}

@end


Типичный метод в языке Objective-C имеет следующие качества.

1. Префикс указывает компилятору, является ли данный код методом экземпляра (—) или методом класса (+). К методу экземпляра можно обратиться лишь после того, как программист выделит и инициализирует экземпляр вашего класса. Получить доступ к методу класса можно, вызвав его непосредственно из этого класса. Не волнуйтесь, если на первый взгляд это кажется сложным. В этой книге мы рассмотрим многочисленные примеры методов, пока просто следите за ходом рассказа.

2. Тип данных для метода, если метод возвращает какое-либо значение. В примере мы указали тип данных void. Так мы сообщаем компилятору, что не собираемся возвращать от метода какое-либо значение.

3. Первая часть имени метода, за которой идет первый параметр. Метод может и не иметь параметров. Методы, не принимающие параметров, довольно широко распространены.

4. Список последующих параметров, идущих за первым.

Рассмотрим пример метода с двумя параметрами:


– (void) singSong:(NSData *)paramSongData loudly:(BOOL)paramLoudly{

/* Параметры, к которым мы можем обратиться здесь, в этом методе, таковы:


paramSongData (для доступа к информации о песне)

paramLoudly сообщает нам, должны мы петь песню громко или нет

*/

}


Важно учитывать, что каждый параметр каждого метода обладает внешним и внутренним именем. Внешнее имя входит в состав метода, а внутреннее имя – это фактическое название (или псевдоним) параметра, которое может использоваться в пределах реализации метода. В предыдущем примере внешнее имя первого параметра – singSong, а внутреннее – paramSongData. Внешнее имя второго параметра – loudly, а внутреннее – paramLoudly. Имя метода и внешние имена его параметров вместе образуют сущность, которая называется селектором метода. В данном случае селектор упомянутого метода будет иметь вид singSong: loudly:. Как будет объяснено далее в этой книге, селектор является идентификатором каждого метода в среде времени исполнения. Никакие два метода в рамках одного и того же класса не могут иметь одинаковые селекторы.

В нашем примере мы определили в файле реализации класса Person (Person.m) три метода:

walkAtKilometersPerHour:;

• runAt10KilometersPerHour;

• singSong: loudly:.

Если бы мы хотели использовать любой из этих методов из какой-нибудь сущности, находящейся вне класса, например из делегата приложения, то должны были бы предоставить эти методы в нашем файле интерфейса (Person.h):


#import <Foundation/Foundation.h>


@interface Person: NSObject


@property (nonatomic, copy) NSString *firstName;

@property (nonatomic, copy) NSString *lastName;


– (void) walkAtKilometersPerHour:(CGFloat)paramSpeedKilometersPerHour;

– (void) runAt10KilometersPerHour;


/* Не предоставляем метод singSong: loudly: для доступа извне.

Этот метод является внутренним для нашего класса. Зачем же нам открывать к нему доступ? */


@end


Имея такой файл интерфейса, программист может вызывать методы walkAtKilometersPerHour: и runAt10KilometersPerHour извне класса Person. А метод singSong: loudly: так вызывать нельзя, поскольку он не предоставлен в файле интерфейса. Итак, продолжим: попробуем вызвать все три этих метода из делегата нашего приложения и посмотрим, что получится:


– (BOOL) application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{


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


[person walkAtKilometersPerHour:3.0f];

[person runAt10KilometersPerHour];


/* Если раскомментировать следующую строку кода, то компилятор выдаст

вам ошибку и сообщит, что такого метода в классе Person не существует */

//[person singSong: nil loudly: YES];


self.window = [[UIWindow alloc]

initWithFrame: [[UIScreen mainScreen] bounds]];

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return YES;

}


Итак, теперь мы умеем определять и вызывать методы экземпляров. А что насчет методов классов? Сначала разберемся, что такое методы классов и чем они отличаются от методов экземпляров.

Метод экземпляра – это метод, относящийся к экземпляру класса. Например, в нашем случае вы можете создать экземпляр класса Person дважды и получить в гипотетической игре, которую разрабатываете, двух разных персонажей. Один персонаж будет ходить со скоростью 3 км/ч, другой – 2 км/ч.

Пусть вы и написали код для метода экземпляра walk всего один раз, но когда во время исполнения создаются два экземпляра класса Person, поступающие от них вызовы методов экземпляра маршрутизируются к соответствующему экземпляру класса (тому, который выполнил вызов).

Напротив, методы класса работают только с самим классом. Например, в вашей игре есть экземпляры класса Light, отвечающего за подсвечивание сцен в вашей игре. У этого класса может быть метод dimAllLights. Вызвав этот метод, программист погасит в игре все источники света независимо от того, где они находятся. Рассмотрим пример метода класса, применяемого с нашим классом Person:


#import "Person.h"


@implementation Person


+ (CGFloat) maximumHeightInCentimeters{

return 250.0f;

}


+ (CGFloat) minimumHeightInCentimeters{

return 40.0f;

}


@end


Метод maximumHeightInCentimeters – это метод класса, возвращающий гипотетический максимальный рост любого персонажа в сантиметрах. Метод класса minimumHeightInCentimeters возвращает минимальный рост любого персонажа. Вот как мы предоставим оба этих метода в файле интерфейса нашего класса:


#import <Foundation/Foundation.h>


@interface Person: NSObject


@property (nonatomic, copy) NSString *firstName;

@property (nonatomic, copy) NSString *lastName;

@property (nonatomic, assign) CGFloat currentHeight;


+ (CGFloat) maximumHeightInCentimeters;

+ (CGFloat) minimumHeightInCentimeters;


@end

Мы добавили к нашему классу Person еще одно свойство, принимающее значения с плавающей точкой. Оно называется currentHeight. С его помощью экземпляры этого класса могут хранить информацию о своей высоте в памяти (для справки) – точно так же, как имя и фамилию.

А в делегате нашего приложения мы продолжим работать с методами вот так:

– (BOOL) application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{


Person *steveJobs = [[Person alloc] init];

steveJobs.firstName = @"Steve";

steveJobs.lastName = @"Jobs";

steveJobs.currentHeight = 175.0f; /* Сантиметры */


if (steveJobs.currentHeight >= [Person minimumHeightInCentimeters] &&

steveJobs.currentHeight <= [Person maximumHeightInCentimeters]){

/* Высота этого персонажа находится в пределах допустимого */

} else {

/* Высота этого персонажа находится вне пределов допустимого */

}


self.window = [[UIWindow alloc]

initWithFrame: [[UIScreen mainScreen] bounds]];

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return YES;

}

iOS. Приемы программирования

Подняться наверх