Переменная 'xxx' никогда не изменялась, рассмотрите возможность изменения на 'let'

Обновлено до xcode7-beta. Я обнаружил предупреждение нового типа. Вот мой код

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect)
    if let layoutInfo = self.layoutInfo {
        attributes?.append(layoutInfo)
    }
    return attributes
}

предупреждающее сообщение Variable 'attributes' was never mutated, consider changing to 'let' constant

Почему xcode говорит Variable 'attributes' was never mutated?

Обновление вопроса

предупреждение исчезло, когда я изменил свой код на этот

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect)
    if let layoutInfo = self.layoutInfo {
        attributes!.append(layoutInfo)
    }
    return attributes
}

поэтому принудительное разворачивание может забрать его. Но это может быть нехорошо, правда?


person dopcn    schedule 10.06.2015    source источник
comment
вы пытались изменить, чтобы позволить? Он все еще компилируется?   -  person Icaro    schedule 10.06.2015
comment
Привет, @Icaro, мне нужно добавить свой layoutInfo, поэтому мне действительно нужен var   -  person dopcn    schedule 10.06.2015
comment
Значит, это ошибка компилятора!   -  person Icaro    schedule 10.06.2015
comment
Я склонен думать, что в данном конкретном случае это может быть ошибка. В iOS 9 SDK было проверено множество классов Cocoa Touch для поддержки универсальных шаблонов Objective-C, и компилятор может сбивать с толку некоторые из этих недавно типизированных массивов NSArrays с типизированными массивами Swift. Использование здесь var предлагает предложение использовать let, но использование let вызывает ошибку.   -  person Mick MacCallum    schedule 10.06.2015
comment
Похоже на ошибку. С attributes!.append(layoutInfo) вместо attributes?.append(layoutInfo) предупреждение исчезает :)   -  person Martin R    schedule 10.06.2015
comment
@MartinR Да, ты прав   -  person dopcn    schedule 10.06.2015


Ответы (5)


Об этом они говорили в видеороликах WWDC и в примечаниях к выпуску.

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

Но компилятор не может этого сделать, если вы не используете let всякий раз, когда можете. Это не изменит var на let для вас.

Следовательно, в Swift 2 компилятор выполняет более интеллектуальный анализ во время сборки и предупреждает вас, если вы используете var там, где вы могли бы использовать let. В конце концов, эта функция заработает правильно, и тогда вам следует прислушаться к совету компилятора!

person matt    schedule 10.06.2015
comment
если вы планируете добавить дополнительный код, в котором вы фактически измените это значение - этот код уже присутствует. - person Martin R; 10.06.2015
comment
@MartinR Это всего лишь бета-версия, поэтому очевидно, что умный компилятор еще не исчерпал себя. Я не сказал, что он работает идеально, я просто описываю, для чего должно быть предупреждение! :) - person matt; 10.06.2015
comment
Если это было правдой, почему все языки программирования в первую очередь используют переменные (а не константы)? Даже язык ассемблера имеет изменяемые регистры! - person Cosmin; 17.10.2017
comment
У вас есть ссылка на оптимизацию производительности? Это, безусловно, безопаснее, и я могу представить себе некоторые оптимизации, но объем памяти остается неизменным, независимо от того, изменяете вы его или нет. - person Justin Meiners; 14.04.2021

Это тоже сводило меня с ума. Всякий раз, когда у меня есть класс и я изменяю свойства члена, он все равно говорит мне, что я должен сделать переменную константой. Например:

class X { 
    var name = ""
}

var xInstance = X()
xInstance.name = "my name"

Насколько я понимаю, компилятор правильный. xInstance - это константа. Ему назначается указатель на экземпляр X во время его инициализации, и ему никогда не присваивается другое значение. Итак, xInstance постоянен. Класс, на который он указывает, не является постоянным. Это более очевидно на таких языках, как C или C ++, но когда вы понимаете, что все экземпляры классов на самом деле являются указателями на классы, поддерживаемые кучей, это имеет смысл.

Для тех, кто разбирается в C ++

xInstance эквивалентен:

X *xInstance

вместо этого создание let означает, что он изменится на:

X * const xInstance

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

X const * xInstance
person Greg Veres    schedule 28.10.2015
comment
Это имеет огромное значение для такой старой окаменелости, как я. let дает вам постоянный указатель на переменный объект. Но вот интересная загвоздка ... если вы объявляете структуру, а не класс, вся структура будет неизменной / постоянной. - person Eli Burke; 02.12.2015
comment
Грег, спасибо за этот ответ! @EliBurke, вы случайно не знаете, почему это произошло? Я не понимаю, как я могу объяснить эту разницу? - person Imran Ahmed; 16.07.2018
comment
Если вы спрашиваете о моем интересном комментарии о морщинах, структуры - это типы значений (например, Ints или Bools). Подумайте о полях структуры так же, как о байтах Int. Найдите swift struct vs class, и на этот счет есть еще много ответов. - person Eli Burke; 17.07.2018

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

Если вы объявляете переменную с помощью var и не собираетесь ее изменять или вызывать для нее методы изменения, вместо этого использование let поможет вам обеспечить выполнение этого контракта.

person rickster    schedule 10.06.2015

Вы создали этот объект как объект var, но значение этого объекта не меняется, а затем лучше разрешить его. Вот и все.

В соответствии с рекомендациями разработчика Apple, создайте объект var, если значение этого объекта изменится, иначе создайте переменную let. Лучшая практика

person Nilesh Patel    schedule 10.06.2015

Ваш код подразумевает, что attributes может быть изменен, если self.layoutInfo не равно нулю

Возможно, в предупреждении говорится, что ни один путь не приводит к self.layoutInfo, отличному от nil, и, следовательно, атрибуты не должны быть var.

Изучите, какие условия, если таковые имеются, могут привести к self.layoutInfo получению данных.

person Warren Burton    schedule 10.06.2015