субота, 22 лютого 2014 р.

@property свойства класса

Ключевое слово @property позволяет объявить свойства класса в языке Objective C. По своей сути свойства являются средством написания кода, позволяющим удобно обращаться к полям класса, не нарушая принципа инкапсуляции и не используя синтаксис вызова методов. Свойства не обязательно должны базироваться на полях класса. Они могут, например, вычисляться во время каждого вызова. Основной смысл использования свойств – более удобный синтаксис в сравнении с обычными вызовами методов. Возможность использовать свойства появилась в языке Objective C начиная с версии 2.0. Для лучшего понимания принципов работы свойств рассмотрим несколько примеров. Предположим, у нас есть класс Car, содержащий поле speed для хранения скорости автомобиля. Тогда объявление этого класса будет выглядеть так:

@interface Car : NSObject {
    double _speed;
}

- (double)speed;
- (void)setSpeed:(double)s;

@end
Сообщения speed и setSpeed позволяют читать и изменять закрытое поле _speed, реализовывая принцип инкапсуляции. Реализация данного класса может выглядеть следующим образом:
@implementation Car

- (void)setSpeed:(double)speed {
    if (speed >= 0) {
        _speed = speed;
    }
}

- (double)speed {
    return _speed;
}

@end
Создание экземпляра этого класса и использование поля могут быть такими:
    Car *car = [[Car alloc] init];
    [car setSpeed:105];
    NSLog(@"%f", [car speed]);
На приведенном выше примере можно увидеть, что чтение значений из полей класса и занесение новых значений синтаксически не очень удобно. Гораздо удобнее было бы напрямую обратиться к полям класса при помощи оператора -> Но тогда поля класса пришлось бы сделать открытыми и было бы невозможно контролировать значения, заносимые в поля. Применение свойств как раз и должно решить эту проблему. С использованием ключевого слова @property объявление класса примет такой вид:
@interface Car : NSObject

@property double speed;

@end
Как видно из примера, при объявлении свойства указывается тип свойства и в данном случае он совпадает с типом поля класса. Так же Objective C допускает одинаковые названия свойств и полей классов. С учётом сделанных изменений, реализация класса будет такой:
@implementation Car

@synthesize speed;

@end
или еще проще (т.к. с Xcode 4 @synthesize реализуются автоматически)
@implementation Car

@end
Упрощение кода в данном случае заметить не трудно. Мы просто убрали реализацию методов доступа к полю _speed и заменили её на автоматическую генерацию поля при помощи ключевого слова @synthesize. Теперь попробуем воспользоваться созданным свойством:
    Car *car = [[Car alloc] init];
    car.speed = 45.5;
    NSLog(@"%f", car.speed);
Вот ради чего всё затевалось. Теперь мы можем обращаться к полю класса при помощи удобного оператора “точка”. В этом и есть основной смысл свойств. Но в этом коде всё ещё есть проблемы. Дело в том, что в поле speed можно запросто занести отрицательные значения. И данное автоматически сгенерированное свойство никак не может этому помешать. Такая реализация свойства не очень-то и полезна для класса Car. Поэтому переделаем реализацию, добавив в неё аксессоры для доступа к полю.
@implementation Car

- (void)setSpeed:(double)speed {
    if (speed >= 0) {
        _speed = speed;
    }
}

- (double)speed {
    return _speed;
}

@end
Теперь свойство не позволит заносить в поле класса отрицательные значения. Несмотря на то, что кода стало больше, свойство защищает поле класса от некорректных значений. На примере можно увидеть, что имя метода, возвращающего значение, совпадает с именем свойства, а имя метода, записывающего новые значения почучается добавлением слова set в начало имени метода, название свойства начинается с большой буквы. В принципе, названия методов-аксессоров можно изменить. Для этого придётся внести изменения в объявление свойства:
@interface Car : NSObject

@property (getter = getSpeed, setter = setSpeed:) double speed;

@end
После таких изменений объявления свойства метод, возвращающий значение свойства должен называться getSpeed, а метод задающий значение свойства, должен называться setSpeed.

Немає коментарів:

Дописати коментар

HyperComments for Blogger

comments powered by HyperComments