Какао — переключение BOOL, не повторяя его имя

Если BOOL имеет хорошее краткое название, достаточно легко записать:

myBOOL = !myBOOL;

Но что, если BOOL имеет длинное имя?

objectWithLongishName.memberWithLongishName.submember.myBOOL = !(objectWithLongishName.memberWithLongishName.submember.myBOOL);  

... не выглядит настолько симпатичным.

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

9
задан alain.janinm 30 April 2012 в 20:20
поделиться

6 ответов

Вот еще один:

MyBooleanYaddaYadda ^= YES;

Это довольно хрупко - он сломается в устаревшем коде C, который подразумевает, что любое ненулевое целое число оценивается как истинное. Но опять же, как и код фреймворка Apple - я встречал случаи в Какао, когда ненулевое, отличное от единицы int, передаваемое как BOOL, не приводило бы к такому же эффекту, как передача YES.

Однако он не полагается на битовую комбинацию YES - только на то, что NO равно 0. Что в значительной степени само собой разумеющееся, учитывая то, как C интерпретирует целые числа как логические значения. Кроме того, он не предполагает фактического типа данных BOOL (который в Какао, кстати, подписанный char ).

Битовый шаблон YES в Какао равен 1. Но это не универсальное соглашение. На некоторых платформах без встроенного логического типа данных целочисленная константа, которая служит логическим значением ИСТИНА, равна -1 - все единичные биты. Это 0xFFFFFFFF, если интерпретировать как беззнаковый. Такое кодирование имеет нечеткое преимущество, заключающееся в том, что побитовое НЕ (оператор ~ в C) эквивалентно логическому НЕ (оператор! В C). То есть ~ 0xFFFFFFFF равно 0, т.е. е. ~ ИСТИНА - ЛОЖЬ. Не работает, если ИСТИНА определено как 1.

10
ответ дан 4 December 2019 в 06:29
поделиться

В (Objective-)C нет очевидного способа сделать то, что вы описали (без использования макроса препроцессора), но смотрите ответ Севы для возможного (хотя потенциально хрупкого) решения. Что более важно, что-то вроде objectWithLongishName.memberWithLongishName.submember.myBOOL указывает на нарушение закона Деметры; вы должны предоставлять submember непосредственно любой единице кода, которой нужен доступ к submember.myBOOL.

9
ответ дан 4 December 2019 в 06:29
поделиться

Написать метод для класса submember, который переключает его для вас?

- (void) toggleMyBOOL {
  self.myBool = !self.myBool;
}

Тогда вы можете сделать:

[objectWithLongishName.memberWithLongishName.submember toggleMyBOOL];
6
ответ дан 4 December 2019 в 06:29
поделиться

Использовать XOR. В C это ^.

BOOL x = YES;
x ^= YES; // it's now NO
x ^= YES; // it's now YES
x ^= YES; // it's now NO
x ^= YES; // it's now YES
x ^= YES; // it's now NO
x ^= YES; // it's now YES
...

Edit: очевидно, кто-то уже опубликовал это. Думаю, я должен сказать, что на самом деле никогда не использовал это в коде. : -)

2
ответ дан 4 December 2019 в 06:29
поделиться

У вас прекрасный набор ответов, сосредоточенных на переключении ДА на НЕТ или наоборот, но нет ответов, которые касались бы того, что представляется архитектурной проблемой в коде.

Ну, некоторые ответы. Я ослеп.

А именно, у вас есть вот это:

objectWithLongishName.memberWithLongishName.submember.myBOOL =
    !(objectWithLongishName.memberWithLongishName.submember.myBOOL);  

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

Обычно вы не проникаете глубоко в слой модели вдоль ключевых путей, чтобы редактировать состояние за пределами слоя Cocoa Bindings (и даже он немного хрупок).

Иногда такие длинные пути действительно имеют смысл. В таком случае, я бы оставил убер-вербозную форму, которую вы привели выше, как визуальное указание на то, что инкапсуляция целенаправленно разрушается.

0
ответ дан 4 December 2019 в 06:29
поделиться
#define NOT(b) (b) = !(b)

NOT(MyBooleanVariableWithAFreakishlyLongName);

Или, если это Objective C++:

inline void NOT(BOOL &b)
{
    b = !b;
}
10
ответ дан 4 December 2019 в 06:29
поделиться