Pergunta

Dos documentos da Apple:

“Cada modificador no nível de acesso acima aceita opcionalmente um único argumento, que consiste no conjunto de palavras-chave entre parênteses (por exemplo, privado (set)).Use esta forma de um modificador de nível de acesso quando deseja especificar um nível de acesso para o setter de uma variável ou subscrito que é menor ou igual ao nível de acesso da variável ou do próprio subscrito, conforme discutido em getters e setters. ”

Trecho de:Apple Inc."A linguagem de programação rápida." iBooks. https://itun.es/ru/jEUH0.l

Um exemplo que tento testar no Playground:

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"

Um erro que recebo na saída do console:

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

O que estou fazendo de errado?Estou esquecendo de algo?

PS1

Este exemplo funciona bem:

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

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

Mais dos documentos:

"O nível de acesso para a propriedade Numberofedits é marcado com um modificador privado (SET) para indicar que a propriedade deve ser coletada apenas dentro do mesmo arquivo de origem que a definição da estrutura do rastreamento".

Trecho de:Apple Inc."A linguagem de programação rápida." iBooks. https://itun.es/ru/jEUH0.l

enter image description here

Mas não é disso que preciso.É possível proibir a definição da variável numberOfEdits fora da estrutura/classe?

Foi útil?

Solução

Seu problema está aqui:

  set { self.name = "Unknown" }

Você está definindo o valor de uma propriedade computada em seu próprio setter.Isso causa recursão infinita.Não esqueça que este é um computado propriedade:na verdade, não tem armazenamento.Você não tem uma variável "self.name" para inserir nada;você só tem algumas funções para calculá-lo.Propriedades computadas como essa devem usar outras variáveis ​​não computadas para armazenamento.(A propósito, é por isso que seu exemplo de estrutura funciona:você está usando um imóvel com armazenamento.)

Você não está sendo ajudado em sua depuração pelo fato de rodar em um Playground.Não me interpretem mal:Os parques infantis são ótimos.No entanto, neste caso, leva alguns segundos para travar, então a falha provavelmente não aparece quando você espera após uma edição.Ele também não mostra um rastreamento completo da pilha (o que é enorme para o problema que você está enfrentando, tendo reproduzido-o em um aplicativo "real" e pode ter tornado mais óbvio que você explodiu a pilha). construiu e executou o acima como um aplicativo de console, ele finalmente explodiu com um rastreamento de pilha de 104.832 chamadas de profundidade, todas menos duas das quais foram ...private_cmd.A.name.setter....Uma pequena pista :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top