2016-10-02 2 views
8

Я тестирую это, и кажется, что если вы измените значение в пределах didSet, вы не получите другой звонок didSet.В Swift, происходит сброс свойства внутри didSet, запускается еще один hasSet?

var x: Int = 0 { 
    didSet { 
     if x == 9 { x = 10 } 
    } 
} 

Могу ли я положиться на это? Это где-то задокументировано? Я не вижу его в документе Swift Programming.

+0

Просто протестирован на игровой площадке Xcode 8 (Swift 3) и получил тот же результат. Если ваше изменение свойства из 'didSet',' didSet' снова вызывается __not__. –

+0

«Могу ли я полагаться на это» Да. – matt

+0

У меня на самом деле был 'didSet' на моем массиве, который в конце также имел' defer', используемый для popping * last *. Угадайте, что случилось? Он разбился, потому что я выталкивал каждый элемент, который делал мой массив пустым, должен был делать 'if else' внутри' defer', поэтому я не буду всплывать, если 'myArray.isEmpty! = True' – Honey

ответ

10

Я также подумал, что это невозможно (возможно, это было не в Swift 2), но я его протестировал и нашел an example, где Apple использует это. (В «запрашивая и установку типа Свойства»)

struct AudioChannel { 
    static let thresholdLevel = 10 
    static var maxInputLevelForAllChannels = 0 
    var currentLevel: Int = 0 { 
     didSet { 
      if currentLevel > AudioChannel.thresholdLevel { 
       // cap the new audio level to the threshold level 
       currentLevel = AudioChannel.thresholdLevel 
      } 
      if currentLevel > AudioChannel.maxInputLevelForAllChannels { 
       // store this as the new overall maximum input level 
       AudioChannel.maxInputLevelForAllChannels = currentLevel 
      } 
     } 
    } 
} 

И ниже этот кусок кода, имеется следующее примечание:

В первом из этих двух проверок, наблюдатель didSet устанавливает currentLevel в другое значение. Это не, однако заставляет наблюдателя снова называться.

+0

Это больше не применяется в Swift 4 и вызовет цикл – thedeveloper3124

+3

@ thedeveloper3124 Я только что протестировал в Swift 4 и все еще работает. – thislooksfun

1

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

Он не рекурсирует, как я подозревал, может, это так, по крайней мере, хорошо.

Я могу придумать несколько случаев, когда было бы приемлемым, чтобы сеттер менял то, что я устанавливаю. Одним из таких примеров может быть переменная, установленная на угол, который автоматически нормализуется как [0, 2π].

+0

Это изменение произошло на Swift 3? Я помню, в Swift 2 был рекурсивный звонок. –

+0

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

0

From Apple docs (курсив мой):

Аналогично, если вы реализуете наблюдатель didSet, она передается постоянный параметр, содержащий старое значение свойства. Вы можете указать параметр или использовать имя параметра по умолчанию для oldValue. Если присваивает значение свойству в своем собственном наблюдателе bySet, новое значение , которое вы назначаете, заменяет только тот, который был только что установлен.

Таким образом, присвоение значения в didSet официально является ОК и не вызывает бесконечную рекурсию.

Смежные вопросы