dev._.note

[Swift] lazy란? 본문

Dev/SWIFT

[Swift] lazy란?

Laena 2024. 1. 10. 18:10

lazy란?

lazy 저장 프로퍼티는 처음 사용되지 전까지 초기값이 계산되지 않는 프로퍼티이다. (메모리에 올라가지 않는다.) 
변수(var) 앞에 lazy를 선언함으로써 사용할 수 있다. 

 

lazy는 var(변수) 앞에 사용

초기 값은 인스턴스 초기화가 완료 될 때까지 검색되지 않을 수 있기 때문에 변수로 선언해야한다.

상수(let)은 초기화가 완료되기 전에 항상 값을 가지고 있는 상태이어야 하기 떄문에 lazy로 선언할 수 없다. 

 

struct Hello {
    init() {
        print("Hello 생성")
    }
}

struct Hello2 {
    init() {
        print("Hello2 생성")
    }
}

struct Hi {
    var name: String
    
    //lazy
    //lazy 키워드를 사용하면 인스턴스 생성이 바로 되지 않는다.
    lazy var hello = Hello()
    //lazy 키워드가 없을 때는 Hi가 생성될 때 Hello2도 같이 인스턴스 생성이 된다.
    var hello2 = Hello2()
    
    init(_ name: String) {
        self.name = name
        print("HI 생성\(name)")
    }
}

var hi = Hi("")
//Hello2 생성
//Hi 생성
//lazy 키워드는 나중에 직접 생성 해줘야 한다.

hi.hello
//Hello 생성

 

lazy 키워드가 없을 때는 Hi struct가 생성될 때, Hello2도 함께 생성되는 것을 볼 수 있다

Hi struct만 생성한 시점에서는 lazy 키워드에 있는 값은 생성되지 않았다. 

hi.hello를 직접 생성한 순간 lazy 키워드가 메모리에 올라가서 프린트가 찍히는 것을 볼 수 있다. 


 

  1. lazy는 반드시 var(변수)와 함께 사용해야 한다. 

  위에서 말한 것과 같이 lazy 변수는 초기값이 나중에 생기기 때문에 let으로 선언이 불가능하다. 

  2. struct, class 에서만 사용이 가능하다. 

  3. Computed Property에 사용될 수 없다. 

  lazy는 처음 사용될 때 메모리에 값을 올리고 그 이후에 계속 메모리에 올라온 값을 사용한다.

  때문에 값을 연산하는 computed property에는 사용할 수 없다. 

  4. lazy에 특별한 연산을 통해 값을 넣어주기 위해서는 클로저를 사용한다. 

  기본적으로 일반 변수는 클래스가 생성된 이후에 접근이 가능하기 때문에 클래스내의 다른 메소드나 프로퍼티에는 self를 통해 접근이 불    가능하다.

  하지만 lazy를 이용하면 생성 후 추후 접근이라는 의미이기 때문에 클로저 내에서 self로 접근이 가능하다. 

 

class Person {
    var name: String
    lazy var greeting: String = {
         return "Hello my name is \(self.name)"
    }()
    
    init(name: String) {
        self.name = name
    }
}

var me = Person(name: "Ann")
print(me.greeting)

me.name = "Chris"

print(me.name)
print(me.greeting)

//Hello my name is Ann
//Chris
//Hello my name is Ann

다음 코드를 보면 ()초기화를 통해 즉시 실행한 후 결과를 돌려주고 끝나버리기 때문에 메모리 누수의 걱정이 없다. 

만약 값을 바꿔주고 싶다면 타입을 string이 아닌 클로저 자체로 만들어주면 가능하다. 

 

class Person2 {
    var name: String
    
    lazy var greeting: () -> String = { [weak self] in
        return "Hello my name is \(self?.name ?? "")"
    }
    init(name: String) {
        self.name = name
    }
}

var me2 = Person2(name: "apple")

print(me2.greeting())

me2.name = "banana"

print(me2.greeting())
//Hello my name is apple
//Hello my name is banana

클로저 자체를 담고 있는 변수라면 [weak self]를 통해 메모리 누수 방지를 해줘야 한다. 

클로저 자체가 메모리에 올라가 있고 self는 내부에서 클로저를 참고하고 있기 때문에 결과값이 바뀌게 된다. 

'Dev > SWIFT' 카테고리의 다른 글

[Swift] replacingOccurrences(of:with:)  (0) 2024.01.30
[Swift-UI] 화면전환하기  (0) 2024.01.11
[Swift] Decodabe, Encodable, Codable  (0) 2024.01.09
[Swift] URLSession  (1) 2024.01.07
[Swift] URL 구성요소  (1) 2024.01.04