티스토리 뷰

Swift + iOS/Swift

[Swift] lazy Variables

군옥수수수 2017. 11. 29. 23:04

Lazy variables


이전의 글들을 보셨거나 스위프트 문법 공부를 해보신 분들이라면 스위프트에서 메모리는 굉장히 예민한 주제인 것을 알 수 있습니다. 저 역시 그렇게 느꼈고, 그런 예민함이 보다 메모리를 효율적으로 관리할 수 있는 방향으로 이어졌습니다. 오늘은 이러한 메모리와 관련된 문법 중 하나인 lazy에 대해 알아보도록 하겠습니다.


이전에 작성한 메모리 관리에 관한 글도 읽어보시기 바랍니다.

[Swift] Retain cycle, weak, unowned


애플의 공식 문서에서는 이렇게 설명하고 있습니다.


"A lazy stored property is a property whose initial value is not calculated until the first time it is used"

직역을 해보자면 lazy 변수는 처음 사용되기 전까지는 연산이 되지 않는다는 것입니다. 이를 보다 이해하기 쉽게 설명해보도록 하겠습니다.


인스타그램을 예로 들어보도록 하겠습니다. 인스타그램을 실행시키면 가장 상단에 본인의 팔로워들의 아이콘들이 존재하고 이 아이콘을 클릭하면 해당 유저가 올린 스토리 영상을 확인할 수 있습니다. 여러분이 인스타그램을 실행시켰을 때 이러한 영상들도 모두 서버로부터 가져오는 작업을 할까요? 만일 여러분이 어플리케이션을 실행하는 동안 한번도 스토리들을 클릭하여 확인하지 않는다면 이는 쓸데 없이 메모리만 차지하고 어플리케이션을 실행할 때 딜레이도 존재할 수 있습니다. 해당 영상들은 여러분이 클릭했을 때만 보여주기만 하면 되기 때문입니다.


즉, 처음 사용되기 전까지는 로드되지 않다가 영상을 보려고 클릭하면 해당 영상들이 서버로부터 로드되는 것입니다.


실제로 lazy 를 사용하지 않아도 이해를 돕기 위해 해당 예를 사용하였습니다.

이처럼 필요하지만 사용하기도 전에 불러오기 부담스러운 것들은 lazy를 통해 선언해주는 것입니다.


lazy를 사용하기 위해서는 다음과 같은 고려사항이 필요합니다.


  1. lazy는 반드시 var와 함께 쓰여야 한다.


    lazy 는 반드시 var와 사용되어야 합니다. 이는 한번만 생각해보시면 쉽게 이해하실 수 있습니다. 기본적으로 lazy로 선언된 변수는 초기에는 값이 존재하지 않고 이후에 값이 생기는 것이기 때문에 let 으로는 선언될 수 없습니다.
  2. struct, class


    기본적으로 lazystructclass에서만 사용할 수 있습니다
  3. lazy vs Computed Property


    Computed Property에는 lazy 키워드를 사용할 수 없습니다. lazy는 처음 사용될 때 메모리에 값을 올리고 그 이후 부터는 계속해서 메모리에 올라온 값을 사용합니다. 사용할 때마다 값을 연산하여 사용하는 Computed Property에는 사용할 수 없습니다.
  4. lazy and closure


    lazy에 어떤 특별한 연산을 통해 값을 넣어주기 위해서는 코드 실행 블록인 closure를 사용합니다.

    classstruct의 다른 프로퍼티의 값을 lazy 변수에서 사용하기 위해서는 closure내에서 self를 통해 접근이 가능합니다. 기본적으로 일반 변수들은 클래스가 생성된 이후에 접근이 가능하기 때문에 클래스내의 다른 영역(메소드, 일반 프로퍼티)에서는 self를 통해 접근할 수 없지만 lazy키워드가 붙으면 생성 후 추후에 접근할 것이라는 의미이기 때문에 closure내에서 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:"John")

print(me.greeting // Hello my name is John

me.name = "James"

print(me.greeting // Hello my name is John

lazy var greeting을 보시면 클로저 내부에서 self.name을 통해 name프로퍼티에 접근하는 것을 보실 수 있습니다. 이전 포스팅을 보셨던 분들이라면 이렇게 클래스 내부의 클로저에서 클래스 객체를 self 로 참조한다면 메모리 누수가 발생하는 위험이 있다는 것을 아실 것입니다. 하지만 뒤의 ()를 통해 그 즉시 실행하고 결과를 돌려주고 끝나버리기 때문에 메모리 누수의 걱정은 없습니다


또한 프로퍼티가 James으로 변경이 되어도 처음 사용할 때 메모리에는 John이 올라가 있기 때문에 John이 출력이 됩니다.

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

var me = Person(name:"John")

print(me.greeting()) // Hello my name is John

me.name = "James"

print(me.greeting()) // Hello my name is James

만일 변수가 lazy var greeting:String이 아닌 lazy var greeting:()->String으로 클로저 실행의 결과를 담는 것이 아닌 클로저 자체를 담고 있는 변수라면 반드시 [weak self]를 통해 메모리 누수를 방지해주어야 합니다.


또한 값이 아닌 클로저 자체가 메모리에 올라가 있고 self 는 내부에서 계속해서 클래스를 참조하기 때문에 계속 John이 출력이 되는 것이 아닌 James가 출력이 되는 것입니다.


마무리

오늘은 이렇게 간단하게 lazy에 대해 알아보았습니다. 계속해서 iOS 제작에 관련된 포스팅을 올리지만 이렇게 스위프트 자체의 문법을 아는 것이 중요하기 때문에 문법 공부를 게을리하지 않고 지속해서 포스팅하도록 노력하겠습니다. 감사합니다.


참고자료


  1. lazy var in ios swift
  2. What are lazy variables
  3. 스위프트 Lazy


'Swift + iOS > Swift' 카테고리의 다른 글

[Swift] String 좀 더 알아보기 (1)  (0) 2018.01.01
[Swift] if-let을 사용할 때 유의해야할 점  (1) 2017.12.17
[Swift] Retain cycle, weak, unowned [번역]  (6) 2017.10.13
[Swift] Protocol [02]  (3) 2017.10.02
[Swift] Closure [02]  (1) 2017.09.29
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함