Swift에서 지연 초기화 된 변수를 다시 초기화합니다.
다음과 같이 초기화 된 변수가 있습니다.
lazy var aClient:Clinet = {
var _aClient = Clinet(ClinetSession.shared())
_aClient.delegate = self
return _aClient
}()
문제는 어떤 시점에서이 aClient
변수 를 재설정해야 ClinetSession.shared()
변경 될 때 다시 초기화 할 수 있다는 것 입니다. 그러나 클래스를 선택 사항으로 설정하면 Clinet?
LLVM으로 설정하려고하면 오류가 발생합니다 nil
. 난 그냥 사용하여 코드 어딘가에을 재설정하면 aClient = Clinet(ClinetSession.shared())
, 그것으로 끝날 것입니다 EXEC_BAD_ACCESS
.
lazy
스스로 리셋 할 수있는 방법이 있습니까?
lazy는 명시 적으로 일회성 초기화를위한 것입니다. 채택하려는 모델은 아마도 주문형 초기화 모델 일 것입니다.
var aClient:Client {
if(_aClient == nil) {
_aClient = Client(ClientSession.shared())
}
return _aClient!
}
var _aClient:Client?
이제 _aClient
가 nil
이면 초기화되고 반환됩니다. 설정을 통해 다시 초기화 할 수 있습니다._aClient = nil
Swift 4에서 의 동작이 lazy
변경 되었기 때문에 저는 struct
언어 버전간에 절대 변경되지 않아야하는 매우 구체적인 동작을 제공 하는 몇 가지를 작성했습니다 . 나는 이것을 BH-0-PD 라이센스에 따라 GitHub에 넣었습니다 : https://github.com/RougeWare/Swift-Lazy-Patterns
ResettableLazy
다음은 값을 지연 초기화하고 해당 값을 캐시하고 나중에 지연 재 초기화 할 수 있도록 삭제하는 방법을 제공하는이 질문과 관련된 질문입니다.
이를 위해서는 Swift 5.1이 필요합니다! Swift 4 버전 의 경우 해당 저장소의 버전 1.1.1을 참조하십시오 .
이것의 간단한 사용법은 매우 간단합니다.
@ResettableLazy
var myLazyString = "Hello, lazy!"
print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"
_myLazyString.clear()
print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"
myLazyString = "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"
_myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
다음과 같이 인쇄됩니다.
Hello, lazy!
Hello, lazy!
Hello, lazy!
Hello, lazy!
Overwritten
Hello, lazy!
이니셜 라이저 로직이 복잡한 경우 속성 래퍼에 전달할 수 있습니다.
func makeLazyString() -> String {
print("Initializer side-effect")
return "Hello, lazy!"
}
@ResettableLazy(initializer: makeLazyString)
var myLazyString: String
print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"
_myLazyString.clear()
print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"
myLazyString = "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"
_myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
직접 사용할 수도 있습니다 (속성 래퍼로 포함됨).
var myLazyString = ResettableLazy<String>() {
print("Initializer side-effect")
return "Hello, lazy!"
}
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"
myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"
myLazyString.wrappedValue = "Overwritten"
print(myLazyString.wrappedValue) // Just returns the value "Overwritten"
_myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
둘 다 다음과 같이 인쇄됩니다.
Initializer side-effect
Hello, lazy!
Hello, lazy!
Initializer side-effect
Hello, lazy!
Hello, lazy!
Overwritten
Initializer side-effect
Hello, lazy!
아래 솔루션은 더 이상 Swift 4 이상에서 작동하지 않습니다!
대신 위에 나열된 솔루션 중 하나 또는 @PBosman의 솔루션 을 사용하는 것이 좋습니다.
아래 동작은 Swift 버그 SR-5172 ( PR # 10,911 로 2017-07-14에 해결됨)에 설명 된 버그이며, 이 동작이 의도적이지 않은 것이 분명합니다.
스위프트 3에 대한 해결책은 역사적인 이유로 이하이지만, 버그이기 때문에 그 3.2 이상 스위프트 작동하지 않습니다 악용 난 당신이 않는 것이 좋습니다 하지 이렇게을 :
이것이 언제 추가되었는지 정확히 모르겠지만 Swift 3 부터는 속성을 nil-able로 만들 수 있습니다. 이제 다음 번에 aClient를로 설정 한 후 호출 하면 다시 초기화됩니다. --- 지금은 기술적으로 선택 사항이지만 읽을 때마다 런타임 값이 보장됩니다. 그게 내가 사용하는 이유입니다 항상 안전 호출이며 않을 것이기 때문에, 여기에, 읽을 로 , 그러나 그것은 할 수 있습니다 설정 에 .
lazy var aClient:Client! = { var _aClient = Client(ClinetSession.shared()) _aClient.delegate = self return _aClient }()
// ...
aClient = nilnil
!
nil
nil
편집 : Ben Leggiero의 답변에 따라, 게으른 변수는 nil
Swift 3에서 가능합니다. 편집 2 : nil
게으른 변수가 더 이상없는 것 같습니다 .
파티에 매우 늦었고 이것이 Swift 3에서 관련이 있는지 확실하지 않지만 여기에 있습니다. David의 대답은 좋지만, 게으른 nil-able 변수를 많이 만들고 싶다면 꽤 많은 코드 블록을 작성해야합니다. 이 동작을 캡슐화하는 ADT를 만들려고합니다. 지금까지 얻은 내용은 다음과 같습니다.
struct ClearableLazy<T> {
private var t: T!
private var constructor: () -> T
init(_ constructor: () -> T) {
self.constructor = constructor
}
mutating func get() -> T {
if t == nil {
t = constructor()
}
return t
}
mutating func clear() { t = nil }
}
그런 다음 다음과 같은 속성을 선언하고 사용합니다.
var aClient = ClearableLazy(Client.init)
aClient.get().delegate = self
aClient.clear()
아직 이것에 대해 마음에 들지 않지만 개선 방법을 모릅니다.
- 보기 흉하게 보이는 이니셜 라이저에 생성자를 전달해야합니다. 그러나 새 개체를 만드는 방법을 정확하게 지정할 수 있다는 장점이 있습니다.
get()
사용할 때마다 속성을 호출 하는 것은 끔찍합니다. 이것이 함수가 아니라 계산 된 속성이라면 약간 더 좋을 것입니다. 그러나 계산 된 속성은 변형 될 수 없습니다.- 호출 할 필요를 없애려면
get()
이니셜 라이저를 사용하여이를 사용하려는 모든 유형을 확장해야합니다ClearableLazy
.
누군가가 여기에서 그것을 집어 들고 싶다고 느낀다면 그것은 굉장 할 것입니다.
이렇게하면 속성을 nil
로 설정하여 강제로 다시 초기화 할 수 있습니다 .
private var _recordedFileURL: NSURL!
/// Location of the recorded file
private var recordedFileURL: NSURL! {
if _recordedFileURL == nil {
let file = "recording\(arc4random()).caf"
let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(file)
NSLog("FDSoundActivatedRecorder opened recording file: %@", url)
_recordedFileURL = url
}
return _recordedFileURL
}
여기에 좋은 답변이 있습니다.
lazy var를 재설정하는 것은 실제로 많은 경우에 바람직합니다.
클라이언트를 생성하고이 클로저로 lazy var를 재설정하기 위해 클로저를 정의 할 수도 있습니다. 이 같은:
class ClientSession {
class func shared() -> ClientSession {
return ClientSession()
}
}
class Client {
let session:ClientSession
init(_ session:ClientSession) {
self.session = session
}
}
class Test {
private let createClient = {()->(Client) in
var _aClient = Client(ClientSession.shared())
print("creating client")
return _aClient
}
lazy var aClient:Client = createClient()
func resetClient() {
self.aClient = createClient()
}
}
let test = Test()
test.aClient // creating client
test.aClient
// reset client
test.resetClient() // creating client
test.aClient
목적이 lazy 속성을 다시 초기화하는 것이지만 반드시 nil로 설정하지 않아도되는 경우, Building from Phlippie Bosman 및 Ben Leggiero, 다음은 값을 읽을 때마다 조건부 검사를 피하는 것입니다.
public struct RLazy<T> {
public var value: T
private var block: () -> T
public init(_ block: @escaping () -> T) {
self.block = block
self.value = block()
}
public mutating func reset() {
value = block()
}
}
테스트하려면 :
var prefix = "a"
var test = RLazy { () -> String in
return "\(prefix)b"
}
test.value // "ab"
test.value = "c" // Changing value
test.value // "c"
prefix = "d"
test.reset() // Resetting value by executing block again
test.value // "db"
Swift 5.1 :
class Game {
private var _scores: [Double]? = nil
var scores: [Double] {
if _scores == nil {
print("Computing scores...")
_scores = [Double](repeating: 0, count: 3)
}
return _scores!
}
func resetScores() {
_scores = nil
}
}
사용 방법은 다음과 같습니다.
var game = Game()
print(game.scores)
print(game.scores)
game.resetScores()
print(game.scores)
print(game.scores)
그러면 다음과 같은 출력이 생성됩니다.
Computing scores...
[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0]
Computing scores...
[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0]
Swift 5.1 and Property Wrapper
@propertyWrapper
class Cached<Value: Codable> : Codable {
var cachedValue: Value?
var setter: (() -> Value)?
// Remove if you don't need your Value to be Codable
enum CodingKeys: String, CodingKey {
case cachedValue
}
init(setter: @escaping () -> Value) {
self.setter = setter
}
var wrappedValue: Value {
get {
if cachedValue == nil {
cachedValue = setter!()
}
return cachedValue!
}
set { cachedValue = nil }
}
}
class Game {
@Cached(setter: {
print("Computing scores...")
return [Double](repeating: 0, count: 3)
})
var scores: [Double]
}
We reset the cache by setting it to any value:
var game = Game()
print(game.scores)
print(game.scores)
game.scores = []
print(game.scores)
print(game.scores)
참고URL : https://stackoverflow.com/questions/25072597/re-initialize-a-lazy-initialized-variable-in-swift
'programing tip' 카테고리의 다른 글
선호 속성 android : dependency의 반대를 수행하는 방법은 무엇입니까? (0) | 2020.11.27 |
---|---|
자바 스크립트 변수 값을 입력 유형 숨겨진 값으로 전달 (0) | 2020.11.27 |
Swift : 튜플을 사용하는 단일 스위치 케이스에서 여러 간격 (0) | 2020.11.27 |
개체에서 가장 높은 값으로 키 가져 오기 (0) | 2020.11.27 |
파이썬에서 정확한 함수 타이밍 (0) | 2020.11.26 |