-
Swift - Stored PropertyProgramming/Swift 2021. 10. 24. 13:30
안녕하세요 Beepeach입니다 :)
오늘 공부해볼 내용은 Property(프로퍼티) 입니다.
프로퍼티란 struct, class, enum 등 타입에 관련된 값을 의미합니다.
프로퍼티라는 이름 때문에 특별해 보이지만 지금까지 우리가 사용했던 상수와 변수가 struct, class, enum에 구현되면 프로퍼티입니다.
특별한 게 아닙니다.
프로퍼티에도 종류가 있습니다.
인스턴스에 관련된다면 Instance property, 타입에 관련된다면 Type property
값을 저장한다면 Stored property, 값을 저장하지 않고 계산을 해서 반환해준다면 Computed property로 구분됩니다.
(이 포스팅에서 type property라는 말이 없다면 instance property를 의미합니다.)
그럼 하나하나 자세히 알아보도록 하겠습니다.
Stored Property(저장 프로퍼티)
저장 프로퍼티는 class와 struct 인스턴스에 저장되는 상수 또는 변수입니다.
enum에서는 사용할 수 없습니다.
Dog 클래스에 name 상수와 age 변수를 선언했습니다.
그리고 Default Value(기본값)을 설정했습니다.
기본값을 설정하면 인스턴스를 생성하면 해당 값으로 초기화됩니다. (초기화에 대해서는 initializer에서 자세히 다루겠습니다.)
우리가 지금까지 사용하던 상수, 변수 선언과 다를 게 없죠??
그럼 struct의 저장 프로퍼티도 보겠습니다.
Struct도 class와 다를 게 없습니다.
이렇게 기본값을 주지 않고 선언할 수 도 있습니다.
한 가지 주의할 점은 class에서는 기본값을 주지 않으면 initializer를 적어도 한 개 이상 구현해줘야 합니다.
한 번 확인해 볼까요??
Dog class가 initializer를 가지지 않았다고 합니다.
그 이유는 struct는 initializer을 구현하지 않아도 Memberwise Initialzer라는 특별한 initializer를 제공합니다.
하지만 classs는 Memberwise Initialzer를 제공하지 않습니다. 그래서 init을 구현하라는 에러가 발생합니다.
자세한 부분은 Init포스팅에서 다루겠습니다.
Property 접근하기
프로퍼티에 접근하는 방법은 InstanceName.(period)를 사용하면 됩니다.
즉 인스턴스를 생성하고 인스턴스와 dot syntax를 이용하여 접근합니다.
인스턴스를 생성하고 한 번 접근해보겠습니다.
Dot syntax로 프로퍼티 값을 읽을 수도 있고 프로퍼티 값을 변경할 수 도 있습니다.
프로퍼티를 let으로 선언하면 초기화 이후에는 값을 변경할 수 없습니다.
Dog나 Cat의 name이 변경되면 이상하겠죠?? 그래서 name프로퍼티는 let으로 선언하고 값이 바뀌지 않는 것을 확인할 수 있습니다.
var로 선언한 age프로퍼티는 초기화 이후에도 변경이 가능합니다.
나이는 매년 바뀌니까 var로 선언하는 게 좋겠죠??
잘 보면 class와 struct의 차이가 보입니다.
둘 다 age 프로퍼티는 변수로 선언했습니다.
그런데 class는 변경이 되는데 struct는 변경이 안되네요??
이유는 인스턴스를 생성할 때 let으로 생성했기 때문입니다. (프로퍼티가 let이 아니라 인스턴스가 let이라는 말입니다. 헷갈리면 안 됩니다.
class는 let으로 인스턴스를 생성해도 var로 선언된 프로퍼티의 값을 변경할 수 있습니다.
struct는 var로 인스턴스를 생성해야 var로 선언된 프로퍼티의 값을 변경할 수 있습니다.
이 차이는 Value type과 Reference type의 차이 때문입니다. 자세한 내용은 이 포스팅을 참고해주세요.
var로 인스턴스를 생성하니 age 프로퍼티를 변경할 수 있는 걸 확인할 수 있습니다.
당연히 var로 인스턴스를 생성해도 let으로 선언된 name 프로퍼티는 변경이 불가능합니다.
Lazy Stored Property (지연 저장 프로퍼티)
Lazy Stored Property 란 해당 프로퍼티에 접근할 시점에 초기화가 이루어지는 프로퍼티를 의미합니다.
위에서 공부했던 저장 프로퍼티는 인스턴스를 초기화함과 동시에 값들이 초기화됩니다.
하지만 lazy stored property는 인스턴스가 초기화될 때 초기화되지 않습니다.
이 프로퍼티에 접근을 할 때 초기화가 이루어집니다.
그럼 언제 지연 저장 프로퍼티를 사용할까요??
프로퍼티의 값이 다른 프로퍼티의 값들이 초기화되고 나서 정해져야 하는 값일 때 사용합니다.
그리고 이미지와 같은 고비용의 값이 꼭 인스턴스가 초기화될 때부터 필요하지 않고 접근할 때만 필요한 값이라면 유용하게 사용됩니다.
그럼 사용 예시를 보겠습니다.
지연 저장 프로퍼티의 문법의 핵심은 lazy 키워드입니다.
그리고 지연 저장 프로퍼티는 반드시 var로 선언되어야 합니다.
이유는 let으로 선언된 constant property(상수 프로퍼티)는 반드시 인스턴스가 초기화되기 전에 값을 가져야 합니다.
상수 프로퍼티는 인스턴스가 초기화된 후에는 값을 변경할 수 없기 때문입니다.
하지만 지연 저장 프로퍼티는 인스턴스의 초기화가 완료된 시점에 초기화가 안됐을 수 있으므로 let으로 선언하는 것은 불가능합니다.
블로그 포스트를 작성하는데 Image는 제목과 내용에 비해 크기가 큽니다.
그래서 BlogPost 인스턴스가 생성되는 시점에 초기화를 하지 않고 접근할 때 초기화가 되도록 구현했습니다.
Line 15까지 실행하면 new image라는 문구가 뜨지 않는 것을 확인할 수 있습니다.
인스턴스가 생성돼도 image 프로퍼티는 초기화되지 않은 것입니다.
하지만 Line 17처럼 post.image와 같이 접근을 하면 그때 new image라는 문구가 나타나는 것을 확인할 수 있습니다.
자 그럼 다음 사용법을 보겠습니다.
title과 content를 모두 보여주는 titleAndContents라는 프로퍼티를 만드려고 합니다.
이번에는 프로퍼티를 선언할 때 클로저를 이용해보았습니다.
클로저 자체를 저장하는 게 아니라 클로저의 결괏값이 저장되어야 하니 Line 10에 ()를 꼭 같이 붙여줘야 합니다.
()가 없다면 String 타입인 titleAndContent 프로퍼티에 Void -> String 타입의 클로저를 저장시키는 문법이 돼버리겠죠??
클로저 마지막에 ()를 사용하면 해당 클로저가 반환하는 리턴 값을 titleAndContent에 저장합니다.
그러니 꼭 ()를 사용해줍시다!
아무튼 여기서 중요한 점은 클로저 안에서 title과 content를 사용하려고 하는데 이 부분에서 에러가 발생합니다.
titleAndContent 프로퍼티가 title, content 프로퍼티보다 아래에 선언되어있다고 해서 인스턴스가 초기화될 때 title의 값이 초기화 완료되고 content의 값이 초기화가 되고 초기화된 값들을 이용한다고 생각할 수 있지만 그렇게 작동하지 않습니다.
Struct나 Class에서 안에서 선언된 프로퍼티에서 다른 프로퍼티에 접근하려면 해당 프로퍼티가 초기화가 완료되어야 합니다.
그럼 저장 프로퍼티에서 다른 프로퍼티를 사용하고 싶은데 이때 어떻게 해야 할까요??
이때 사용하는 게 lazy stored property입니다.
앞에 lazy를 붙여주니 에러가 사라진 것을 확인할 수 있습니다.
그리고 프로퍼티에 접근하면 우리가 원하는 결과가 출력되는 것을 확인할 수 있습니다.
주의할 점은 Struct에서 지연 저장 속성을 사용하고 싶다면 해당 인스턴스도 var로 선언해줘야 합니다.
Struct에서 인스턴스를 let으로 선언하면 인스턴스 초기화 이후에 프로퍼티도 초기화할 수 없으니 에러가 발생합니다.
그렇다면 Class에서는 당연히 괜찮겠죠??
struct를 class로 바꿔주니 에러가 발생하지 않는 것을 확인할 수 있습니다.
이유는 이전에도 말씀드렸듯이 구조체는 ValueType이기 때문입니다.
프로퍼티를 다 끝내려 했는데 생각보다 길어져서 다음 포스팅에서는 Computed Property에 대해서 공부해보도록 하겠습니다!
참고자료
https://docs.swift.org/swift-book/LanguageGuide/Properties.html
728x90'Programming > Swift' 카테고리의 다른 글
Swift - Property Observer (0) 2021.10.26 Swift - Computed Property (0) 2021.10.25 Swift - Value type vs Reference type (0) 2021.10.23 Swift - Struct & Class (0) 2021.10.20 Swift - Enumeration CaseIterable (0) 2021.10.18