프로젝트를 진행하면서 아래와 비슷한 느낌으 코드를 봤다..
class Test {
lazy var a: Int = 1
lazy var b: Int = 1
lazy var c: Int = 1
lazy var d: Int = 1
lazy var e: Int = 1
...
}
왜인지 모르게 lazy를 남발하는 것은 나에게 불편함을 야기했다.
의미자체에서 오는 부정적인 영향인지 메모리에 allocated되는 타이밍을 알 수 없는 것 때문인지 부정적으로 비춰졌다... 하지만 진짜 부정적인가에 대해서는 미지수 였다.
당연히 장점없는 것은 없다.
Lazy는 메모리에 오히려 매우 건강한 키워드이다.
iOS는 민감해서 메모리를 너무 많이 차지하게 되면 터져버린다.
그렇기에 우리는 메모리를 항상 신경써야하는데...
Lazy는 그 방면에서 큰 도움을 준다.
import Foundation
class Test {
init() {
print("I'm here")
}
}
class Laboratory {
lazy var testInstance = Test()
}
var test = Laboratory()
이렇게 되도 아직 testInstance는 메모리에 올라가지 않는다 즉 초기화 되지 않는다. 그렇기 때문에 print는 나오지 않는다.
import Foundation
class Test {
init() {
print("I'm here")
}
}
class Laboratory {
lazy var testInstance = Test()
}
var test = Laboratory()
let isMemoryOn = test.testInstance
반대로 이렇게 하게 되면 print된다.
즉 runtime에 드물게 사용하는 것이 있다면 lazy를 붙이는게 메모리에 도움을 준다.
또 다른 장점은 초기화시에 self를 쓸 수 있다.
class Test {
private var name = "kio"
lazy var message = { [weak self] in
guard let self = self else { return "" }
return "Hello, my name is " + self.name
}()
}
하지만 기본적으로 @nonescape이기 때문에 위와 같이 클로져를 담고있는 경우가 아니면 메모리 누수를 걱정안해도 된다.
장점이 있는데 단점이 있는 것은 없다.
그것도 좀 치명적인데, lazy는 ThreadSafe하지 않다.
즉 여러곳에서 동시에 접근한다면 여러번 초기화될 수 있다. 이는 예상못 할 사이드 이펙트를 야기할 수 있다.
나는 개인적으로 좋은 코드는 우선은 잘 되야된다고 생각하는데 그걸 어길 수 있는것이다.
이슈를 보면 Lazy를 왜 Thread Safe하게 만들지 않느냐하는 글이 있지만... 이 또한 무슨 의미인가 싶다.
결국 이를 Thread Safe하게 하려면 Semaphore처럼 어떤 로직과 공간을 가져야하고 이는 낭비가 된다.
Lazy는 메모리를 사용하지 않을 때 메모리를 아낄 수 있는 장점으로 사용하는 것인데... 이는 배보다 배꼽이 더 커지는 격이지 싶다...
사실 공부를 하면서 Lazy에 대한 부정적인 시선은 사라졌다. 물론 Thread가 동시에 접근하는 곳에는 사용할 수 없지만 그걸 개발자가 철저히 통제할 수 있다면 생각보다 많은 곳에 사용할 수 있을 것 같다.
실제로 then을 사용하는 이유는 코드를 한 곳에서 공통되게 초기화시키는데 있다고 생각한다. lazy는 self를 쓸 수 있기 때문에 이만큼 큰 장점을 가질 수 있다고 생각한다. 하지만 자주 불리고 init에서 반드시 불리는 것들은 lazy로 만들면 시간을 낭비할 수 있고, Thread를 많이 사용하다보면 어떤 side effect가 발생할지 알 수 없다.