Почему private (set) не работает в Swift?

из документов Apple:

" каждый модификатор уровня доступа выше опционально принимает один аргумент, состоящий из набора ключевых слов, заключенного в скобки (например, private (set)). Используйте эту форму уровня доступа модификатор, если требуется указать уровень доступа для задатчика переменная или индекс, который меньше или равен уровню доступа переменная или сам индекс, как описано в Getters и Инкубационные шкафы."

Выдержка Из: Apple Inc. "Язык Программирования Swift."в iBooks. https://itun.es/ru/jEUH0.l

пример, который я пытаюсь проверить на игровой площадке:

import UIKit


class A {
  private(set) var name: String {
  get { return "Hello, (self.name)" }
  set { self.name = "Unknown" }
  }

  init(_ name:String) {
    self.name = name
  }
}

let a = A("Andrew")
a.name = "Hello"

ошибка, которую я получаю в выводе консоли:

Playground execution failed: error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x7fff5056eff8).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
* thread #1: tid = 0xea721, 0x00000001104f308c libsystem_pthread.dylib`__mtx_droplock + 222, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7fff5056eff8)
  * frame #0: 0x00000001104f308c libsystem_pthread.dylib`__mtx_droplock + 222
    frame #1: 0x00000001104f2f07 libsystem_pthread.dylib`pthread_mutex_unlock + 68
    frame #2: 0x000000010ffbd2b5 libc++.1.dylib`std::__1::mutex::unlock() + 9
    frame #3: 0x000000010f040b94 libswift_stdlib_core.dylib`swift_getGenericMetadata + 260
    frame #4: 0x000000010ef28a24 libswift_stdlib_core.dylib`Swift.IndexingGenerator.init <A : Swift._Collection>(Swift.IndexingGenerator<A>.Type)(A) -> Swift.IndexingGenerator<A> + 164
    frame #5: 0x000000010ef55f1a libswift_stdlib_core.dylib`protocol witness for Swift._Sequence_.generate <A : Swift._Sequence_>(@inout Swift._Sequence_.Self)() -> Swift._Sequence_.Self.GeneratorType in conformance Swift._ContiguousArrayBuffer : Swift._Sequence_ + 154
    frame #6: 0x000000010ef284d5 libswift_stdlib_core.dylib`Swift._copyCollectionToNativeArrayBuffer <A : protocol<Swift._Collection, Swift._Sequence_>>(A) -> Swift._ContiguousArrayBuffer<A.GeneratorType.Element> + 1061
    frame #7: 0x000000010ef40281 libswift_stdlib_core.dylib`Swift.Array.convertFromArrayLiteral <A>(Swift.Array<A>.Type)(Swift.Array<A>...) -> Swift.Array<A> + 641
    frame #8: 0x000000010f1eaae4 PlaygroundLogger`Swift.UInt64.toBytes (Swift.UInt64)() -> Swift.Array<Swift.UInt8> + 292
    frame #9: 0x000000010f1eb6a4 PlaygroundLogger`protocol witness for PlaygroundLogger.ToBytes.toBytes <A : PlaygroundLogger.ToBytes>(@inout PlaygroundLogger.ToBytes.Self)() -> Swift.Array<Swift.UInt8> in conformance Swift.UInt64 : PlaygroundLogger.ToBytes + 20
    frame #10: 0x000000010f1dbe3d PlaygroundLogger`PlaygroundLogger.BytesStream.write (PlaygroundLogger.BytesStream)(PlaygroundLogger.ToBytes) -> PlaygroundLogger.BytesStream + 77
    frame #11: 0x000000010f1dbd74 PlaygroundLogger`PlaygroundLogger.BytesStream.write (PlaygroundLogger.BytesStream)(Swift.String) -> PlaygroundLogger.BytesStream + 164
    frame #12: 0x000000010f20f04b PlaygroundLogger`PlaygroundLogger.PlaygroundWriter.encode_config_info (PlaygroundLogger.PlaygroundWriter)() -> () + 203
    frame #13: 0x000000010f20f2bf PlaygroundLogger`PlaygroundLogger.PlaygroundWriter.encode_header (PlaygroundLogger.PlaygroundWriter)() -> () + 127
    frame #14: 0x000000010f20ecda PlaygroundLogger`PlaygroundLogger.PlaygroundScopeWriter.encode_scope_event (PlaygroundLogger.PlaygroundScopeWriter)(PlaygroundLogger.ScopeEvent) -> () + 58
    frame #15: 0x000000010f1eb997 PlaygroundLogger`playground_log_scope_entry + 87
    frame #16: 0x000000011ae20771

что я делаю не так? Я что-то упускаю?

PS1

этот пример прекрасно работает:

struct TrackedString {
  private(set) var numberOfEdits = 0
  var value: String = "" {
  didSet {
    numberOfEdits++
  }
  }
}

var stringToEdit = TrackedString()
stringToEdit.value = "Hello"
stringToEdit
stringToEdit.numberOfEdits += 10
stringToEdit

Подробнее из docs:

"доступ уровень свойства numberOfEdits помечен модификатор private(set), указывающий, что свойство должно быть настраиваемым только из того же исходного файла, что и структура TrackedString определение."

Выдержка Из: Apple Inc. "Язык Программирования Swift."в iBooks. https://itun.es/ru/jEUH0.l

enter image description here

но это не то, что мне нужно. Можно ли запретить устанавливать переменные numberOfEdits вне структура / класс?

1 ответов


ваша проблема кроется здесь:

  set { self.name = "Unknown" }

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

вам не помогает в отладке факт запуска на игровой площадке. Не поймите меня неправильно: игровые площадки-это здорово. Однако в этом случае для сбоя требуется много секунд, поэтому сбой, вероятно, не отображается, когда вы ожидаете после редактирования. Он также не показывает вам полную трассировку стека (которая является массивной для проблемы, которую вы получаете, воспроизведя ее в" реальном " приложении, и, возможно, сделала ее более очевидной что ты все испортил.) Когда я построил и запустил выше как консольное приложение, он, наконец, взорвался со стеком трассировки 104,832 вызовов глубоко, все, кроме двух из которых были ...private_cmd.A.name.setter.... Подсказка :)