синтаксис точки против синтаксиса метода с помощью getter = - PullRequest
12 голосов
/ 10 февраля 2012

Я не уверен, насколько полезен этот вопрос, но мне он кажется интересным ...

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

// .h
@property (nonatomic) BOOL on;

// .m
@synthesize on = _on;

// In my mind synthesizes the following methods

// - (BOOL)on;
// - (void)setOn:(BOOL)on;

Однако, если я изменю декларации на следующие:

                              v
@property (nonatomic, getter=isOn) BOOL on;

@synthesize on = _on;

// In my mind synthesizes the following

// - (BOOL)isOn;
// - (void)setOn:(BOOL)on;

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

- (BOOL)isOn;
{
    NSLog(@"I was called");
    return _on;
}

Теперь вызов следующего для экземпляра (myClass) приводит к:

NSLog(@"%d", [myClass isOn]);

//=> 2012-02-09 22:18:04.818 Untitled[1569:707] I was called
//=> 2012-02-09 22:18:04.820 Untitled[1569:707] 1

NSLog(@"%d", myClass.isOn);

//=> 2012-02-09 22:18:24.859 Untitled[1599:707] I was called
//=> 2012-02-09 22:18:24.861 Untitled[1599:707] 1

NSLog(@"%d", myClass.on);         // This is the one I didn't expect to work

//=> 2012-02-09 22:18:55.568 Untitled[1629:707] I was called
//=> 2012-02-09 22:18:55.570 Untitled[1629:707] 1

Я всегда предполагал, что если бы я использовал свойство в этом смысле, было бы совершенно правильно использовать метод получения / установки с точечным синтаксисом в форме

myClass.isOn;
myClass.on = on;

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

myClass.on   // Correct
myClass.isOn // Incorrect

Хотя это работает, это кажется немного менее логичным, потому что я знаю, что нет базового метода - (BOOL)on, вместо этого он сопоставлен с - (BOOL)isOn

Мои вопросы (на последнем примере)

  • Является ли это ошибкой или myClass.on действительно нужно молча изменить на вызов - (BOOL)isOn
  • С семантической точки зрения, я обращаюсь к состоянию, а не к поведению, так правильно ли мое текущее использование синтаксиса точек? (например, myClass.isOn)

Обновление

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

Однако мне все еще неясно, где происходит "волшебная" проводка, которая превращает вызовы на myClass.on в [myClass isOn]


Обновление 2

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

id MyClass = objc_getClass("MyClass");
unsigned int outCount, i;

objc_property_t *properties = class_copyPropertyList(MyClass, &outCount);
for (i = 0; i < outCount; i++) {
    objc_property_t property = properties[i];
    NSLog(@"Name: %s, attributes: %s\n", property_getName(property), property_getAttributes(property));
}

//=> 2012-02-10 07:10:28.333 Untitled[934:707] Name: on, attributes: Tc,GisOn,V_on

Итак, у нас есть следующие атрибуты:

  • name = on
  • type = char (Tc)
  • getter = isOn (GisOn)
  • переменная = _on (V_on)

Имея всю эту информацию, доступную во время выполнения, она как бы оставляет вопрос: выполняется ли этот поиск во время выполнения или во время компиляции, как предлагают некоторые ответы?

Ответы [ 4 ]

4 голосов
/ 10 февраля 2012

Однако мне все еще неясно, где происходит "волшебная" проводка, которая превращает вызовы myClass.on в [myClass isOn]

Логика, безусловно, выглядит следующим образом при компиляцииимя obj.name в контексте получения:

if(there is an accessible @property for name in scope)
{
   if(there is a custom getter specified)
      compile "[obj customGetter]"
   else
      compile "[obj name]"
}
else if (there is an an accessible instance method name in scope)
   compile "[obj name]"
else
{
   compile "[obj name]"
   warn obj may not respond to name
}

Существуют и другие способы, в которых среда языка / исполнения может обрабатывать пользовательские имена получателей, но, учитывая, что Obj-C помещает объявление в заголовок (который является открытым)Приведенное выше является хорошим предположением относительно того, где выполняется пользовательская логика получения - при компиляции сайта вызовов.

3 голосов
/ 10 февраля 2012

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

  • есть свойство с этим именем?Если так, у него есть указанное имя получателя / установщика?если так, давайте назовем этот метод.
  • в противном случае, составьте подходящее имя метода (direct, если мы получаем, setXX, если мы устанавливаем) и бросим его в приемник.

Например, вы можете попробовать использовать .count против экземпляра NSArray.Перед тем, как полиция мерзости выбьет ваши двери, вы можете успеть убедиться, что это работает.

Чтобы действительно ответить на ваш вопрос, на мой взгляд, точечная нотация должна использоваться только для доступа к свойствам, и в этом случае вы должны использовать имя свойства, как объявлено в интерфейсе.Так что для UISwitch.Я не знаю, почему имя получателя не дается в выражении synthesize вместо объявления свойства, оно, кажется, принадлежит реализации, а не интерфейсу для меня.

2 голосов
/ 10 февраля 2012

Что касается точечной записи, позвольте мне привести Аарона Хиллегаса («Какао-программирование для Mac OSX», 3-е изд.):

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

Когда у вас включена переменная-член, и ваш метод получения этой переменной называется isOn, тогда .on и .isOn - это два совершенно разных вида вещей. Используя getter (и, возможно, также setter), вы будете придерживаться обещания «скрытия информации», тогда как, используя прямой доступ к переменным-членам, вы этого не сделаете. Какао не навязывает эти вещи, поскольку полагается на соглашения. Вам решать, какой путь вам подходит. Принимая во внимание соглашение, вам придется придерживаться методов установки и получения - независимо от того, какие имена вы им дадите.

1 голос
/ 10 февраля 2012

Объявления свойств - это просто сокращение для обычных объявлений методов.Например:

@property int color;
@property (getter=isOn) BOOL on;

становится этими объявлениями метода:

- (int)color;
- (void)setColor:(int)value;
- (BOOL)isOn;
- (void)setOn:(BOOL)on;

Вы можете вызывать эти методы точно так же, как любой другой метод:

[foo color];
[foo isOn];

Аналогично, точечная нотацияпросто неофициальное сокращение для вызова простых старых методов.Например:

x = @"Hello".length;
x = foo.on;
x = foo.isOn;

становится

x = [@"Hello" length];
x = [foo isOn];
x = [foo isOn];

Обратите внимание, что @"Hello".length работает, даже если NSString фактически не объявляет свойство с именем length.По умолчанию foo.bar всегда расширяется до [foo bar] , если bar не объявлено как свойство с пользовательским геттером.Если bar окажется именем допустимого метода, то он будет работать без ошибок.

Аналогично, в вашем примере foo.isOn работает, даже если вы фактически не объявляете свойство с именем "isOn".Скорее «isOn» - это имя метода, который просто является методом получения для вашего свойства «on».

Так что, хотя foo.isOn может работать, это считается плохой формой, поскольку isOn не являетсяна самом деле это имя свойства.

То, что вы не можете сделать, это:

x = [foo on]; // Error

, потому что вы никогда не объявляете метод on.

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