[Objective-C ++] Почему назначение объекта переменной типа BOOL разрешено в 64-битной, но не в 32-битной - PullRequest
0 голосов
/ 20 ноября 2018

Следующий код в ViewController.mm будет успешно скомпилирован (без каких-либо предупреждений или ошибок) в 64-битной среде.

- (void)viewDidLoad {
    [super viewDidLoad];
    BOOL var = [[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];
    NSLog(@"%d", var);
}

Но когда я изменяю цель выполнения на 32-битное устройство (например,, iPhone 5), он показывает мне ошибку следующим образом:

 Cannot initialize a variable of type 'BOOL' (aka 'signed char') with an rvalue of type 'id _Nullable'

Я знаю, что это задание нарушается, но почему оно разрешено в первой ситуации?

Ответы [ 4 ]

0 голосов
/ 31 марта 2019

Несколько вещей играют в пользу того, почему это работает, многие из них исторические вещи, которые существуют только потому, что так было раньше.

  1. bool - это относительно новый тип.Если вы посмотрите на более старый код C, вы часто увидите, что они просто используют int или делают это подобно компилятору Objective-C и объявляют свой собственный тип Bool, BOOL или Boolean.

  2. Назад, когда Objective-C был первоначально определен, они использовали наименьший возможный тип (signed char) для их типа BOOL.

  3. C *Оператор 1020 * всегда разрешает использовать указатель в качестве своего условия, чтобы проверить, что указатель не является NULL (или nil в случае ObjC).

  4. Когда было добавлено boolв соответствии со стандартом C, он был в основном определен как «тип, который принимает if», и поэтому должен был иметь все то же поведение, в том числе позволять вам указывать, где ожидался бул, и оценивать его как falseесли nil, true в противном случае.

  5. Apple не удалось изменить BOOL на bool на старых машинах, потому что это изменило бы символ, который @encode() будетвернулись за BOOL и сделали старые программы не связанными с тем же процессом, что и new библиотеки (и наоборот).

  6. Когда пришла 64-битная iOS, многие типы данных уже изменили размер, поэтому Apple смело сменила там BOOL на bool,потому что не было старых программ, которые должны были бы работать в том же пространстве памяти, что и новые библиотеки.Все было новым.

Так что на платформах, которые имеют новое определение BOOL как bool, вы сталкиваетесь с функцией обратной совместимости С, позволяющей вам проверять NULLуказатели.На старых платформах BOOL определяется как signed char, который явно не подходит для указателя и не имеет специального соуса для указателей, поэтому выдает предупреждение.

0 голосов
/ 20 ноября 2018

ваш код:
BOOL var = [[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];
присваивает адрес объекта по существу целому числу некоторого размера ...

Это почти всегда не то, что вы хотите.Вы, вероятно, хотите:
BOOL var = [[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"]boolValue];

Если вы хотите назначить на основе наличия этого объекта, вы можете сделать:
BOOL var = !![[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];

Причина в том, что еслимладшие 8 битов адреса должны были быть равными 0, это мог быть допустимый объект, но это было бы ложное значение, которое было бы результатом усеченного присваивания.

int main(int argc, const char * argv[]) {

    BOOL b = 2;
    if (b == YES)
    {
        NSLog(@"I guess you are right");
    }else{
        NSLog(@"nope");
    }

print: nope

0 голосов
/ 20 ноября 2018

Для 64-битной iOS тип BOOL использует тип C99 _Bool (иногда также доступен как bool). Этот тип определен так, чтобы иметь только два значения: 0 или 1. Присвоение любого другого значения переменной этого типа приводит к тому, что оно принимает значение 1. (То есть все ненулевые значения становятся 1.)

Таким образом, присвоение не будет усекать побитовое значение, потенциально преобразуя ненулевое значение в ноль. Следовательно, в определенном отношении это «безопасно», и нет повода для предупреждения. (Это может все еще быть удивительным для наивного разработчика, который не понимал разницы между указателем объекта и его значением, как говорили другие ответы, но это совсем другое.)

0 голосов
/ 20 ноября 2018

Ошибка говорит о том, что вы назначаете объект переменной типа BOOL. Чтобы решить эту проблему, вам нужно преобразовать объект, возвращенный из objectForKey: в переменную BOOL, используя boolValue.

BOOL var = [[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"] boolValue];
...