Задача C назначение вызывающего сеттера?

У меня есть поле:

@interface SomeClass : NSObject

@property(nonatomic, nullable) BOOL questionCreated;
@property(nonatomic, nullable) NSString question;

Если я создаю сеттер для вопроса, как:

-(void)setQuestion:(NSString)question {
  _question = question;
  _questionCreated = YES;
}

А затем в другом файле предположим, что у меня есть экземпляр SomeClass именем someClassInstance .

Если я сделаю что-то вроде:

someClassInstance.question = "manually set question"

к моему удивлению, я вижу, что someClassInstance.questionCreated теперь также имеет значение YES , что заставляет меня поверить, что он вызывает метод setter напрямую, если я выполняю someClassInstance.question . Почему это так и как я могу принудительно установить только одно поле?

Всего 1 ответ


Эта строка кода:

someClassInstance.question = @"manually set question";

такой же, как эта строка кода:

[someClassInstance setQuestion:@"manually set question"];

И под «тем же самым» я подразумеваю, что первое преобразуется во второе во время компиляции. Вот что означает «точечная нотация» в Objective-C.

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

Как правило, внешние объекты не должны беспокоиться о внутренних деталях сеттера. Если они есть, что-то неправильно спроектировано (я бы, вероятно, переименовал setQuestion во что-то другое).

Но другой подход заключается в предоставлении прямого сеттера. Это чаще всего префикс «примитив», как:

- (void)setPrimitiveQuestion:(NSString *)question {
    _question = question;
}

И затем вы строите setQuestion поверх этого:

- (void)setQuestion:(NSString *)question {
    [self setPrimitiveQuestion: question];
    self.questionCreated = @YES;
}

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

someClassInstance->_question = @"...";

Но не делайте этого, если вы действительно не знаете, что делаете.