-
Swift4 : 프로퍼티 : #Properties : #get, set " #willSet,didSet스위프트: Swift/스위프트: 언어자체: 문법 2018. 9. 5. 17:00
안녕하세요 ! 씩이 입니다!
저는 Swift 와 iOS 를 공부하고 연구하는 대딩 ( 대학생 ) 이구요!
같은 분야를 공부하는 분들에게 조금이라도 도움이 됬으면 좋겠습니다.
공유가 미래 라고 생각합니다.
한국의 모든 개발자분들 존경합니다!
- Swift version : Swift 4.2 ( 18.09. 01 ~ ) Swift 언어
- 참고한 것들
( 제 깃허브에 iOS, Swift 관련 정보들 정리되어 있습니다!! )
- 스위프트로 구현한 자료구조 : DataStructures in Swift4
- Swift4 : 연결리스트 (1 / 3) : #LinkedList : #DataStructrue : #자료구조
- Swift4 : 연결리스트 (2 / 3) : #LinkedList : #값 추가하기, push, append : #값 삽입하기,insert
- Swift4 : 연결리스트 (3 / 3) : #LinkedList : #값 제거하기, pop, removeLast, remove(at: )
- Swift4: 스택: #Stack: #자료구조: #DataStructure: #쌓기
- Swift4: 큐 (1 / 4): Queue: #자료구조: #배열로 구현한 큐: #배열의원리
- Swift4: 큐 (2 / 4): Queue: #자료구조: #연결리스트: #더블연결리스트: #DoublyLinkedList
- Swift4: 큐 (3 / 4): Queue: #자료구조: #Stack으로 구현: #더블스택: #DoubleStack: #제일좋음
- Swift4: 큐 (4 / 4): Queue: #자료구조: #RingBuffer: #링버퍼로 구현한 큐: #고정된배열: #마지막!!
- Swift 주제별 분류
- Swift4 : 제어 전달 명령문( Control Transfer Statement ) : #continue, #break, #return 키워드
- Swift4 : 클래스와 구조체 : #값을 대하는 방식 : #참조타입, 값 타입 : #===
- Swift4 : 프로퍼티 : #Property : #get, set : #willSet, didSet
- Swift4 : 메소드 : #Method : #영향력 범위 : #self : #mutating : #값타입 수정
- Swift4 : 프로토콜 1 : #Protocol : #설계 : #요구사항 : #델리게이트 패턴 전처리 (1 / 2)
- Swift4 : 프로토콜 2 : #델리게이트 패턴 : #델리게이션 (2 / 2)
- Swift4 : 제네릭 : #Generics : #왜필요해? : #where키워드 : #제약사항걸기
- Swift4 : 자동 참조 카운팅 : #Automatic Referece Counting : #ARC :#강한참조 : #Strong Reference Cycle : #메모리 누수
프로퍼티 : Properties
- 프로퍼티 ? : What is property ?
프로퍼티는 특정 클래스, 구조체 혹은 열거형등과 값을 연결하는 것입니다. 즉 클래스나 구조체, 열거형 등의 객체에 정의된 변수나 상수 인 것이죠.
- 왜 굳이 프로퍼티 라고 하는 거야?
변수나 상수라는 이름을 두고 굳이 프로퍼티 라고 하는 이유는 클래스나 구조체 등 안에 정의된 상수나 변수들은 많은 역할을 수행할 수 있고 여러가지 특성이 있기 때문입니다.
- 종류를 굳이 나누자면 3가지로 나뉩니다.
- 저장 프로퍼티 : Stored Property
- 프로퍼티 옵저버 : 프로퍼티 값의 변화를 감시하여 값의 변화에 따라 특정 행동을 취할 수 있다. 이것이 프로퍼티 옵저버.
- 열거형에는 지원되지 않음. ( 열거형에는 저장프로퍼티를 쓸 수 없다는 말. )
- 연산 프로퍼티 : Computed Property
- 타입 프로퍼티 : Type Property : 저장 , 연산프로퍼티는 보통 특정 타입의 인스턴스와 연결되는데, 인스턴스가 아닌 타입 그 자체로 열결되는 것.
- 저장 프로퍼티 : 값을 저장하는데 사용하는 프로퍼티
- 상수 구조체 인스턴스일 경우 저장 프로퍼티 변경할 수 있어? : NO : 값 타입의 구조체 인스턴스가 상수로 정의 되었다면, 그 인스턴스의 모든 프로퍼티들도 상수로 정의되는 것. ( 구조체가 아닌 구조체에서 받은 인스턴스 임을 주의 )
- 상수 클래스 인스턴스일 경우 저장 프로퍼티 변경할 수 있어? : Yes : 참조 타입의 클래스 인스턴스가 상수로 정의 되었어도, 인스턴스에 저장되 있는 값은 '참조 정보' 일 뿐이므로, 그 참조정보에 접근해서 프로퍼티 변경해도 '참조 정보'가 변하는 것은 아니므로 가능하다.
- 1234567891011121314151617181920struct FixedLengthRange_struct { // 구조체var firstValue: Intlet length: Int}class FixedLengthRange_class { // 클래스var firstValue: Intlet length: Int}let rangeOfFourItems_struct = FixedLengthRange_struct(firstValue: 0, length: 4)// this range represents integer values 0, 1, 2, and 3// FixedLengthRange_struct 의 값을 복사한 새로운 인스턴스를 상수 let rangeOfFourItems_struct 에 저장한 것.rangeOfFourItems_struct.firstValue = 6// rangeOfFourItems_struct 는 상수이므로 해당 인스턴스 정보를 변경할 수 없다. 에러!let rangeOfFourItems_class = FixedLengthRange_class(firstValue: 0, length: 4)rangeOfFourItems_class.firstValue = 6// rangeOfFourItems_ class 는 참조정보만 저장하고 있기 때문에 let 가능
cs
- 지연 저장 프로퍼티 ( lazy 키워드 ) : 지연 저장 프로퍼티는, 즉 lazy 키워드가 붙은 프로퍼티는 그 프로퍼티가 실제로 처음 사용되기 전까지 초기값을 설정하지 않는 프로퍼티이며, 항상 변수로 지정해야 한다. ( var , let이 아닌 )
- 지연 저장 프로퍼티는 왜 항상 변수로?
- 그 이유는 상수 프로퍼티는 항상 초기화가 완료되기 전에 값을 가지고 있어야 하는데 '지연 저장 프로퍼티' 는 초기화 후, 그리고 이 프로퍼티가 호출되기 전까지 초기화 되지 않는 상태이다. ( 공백이 존재한다고 생각하면 됩니다! ) 그러므로 상수를 쓸 수 없는 것.
- 언제 써먹어??
- 프로퍼티의 초기값이 복잡하거나, 계산에 많은 메모리를 쓰는 것일 때 사용한다. 즉, 많은 에너지를 쓰는 과정을 조금 미룸으로써 효율성을 높이는 원리인 것. ( 정확히 말하면 생길수도, 생기지 않을 수도 있는 복잡한 문제는 생기고 난 후에 생각해서, 쓸떼없는 걱정을 하지 말자. 는 뉘앙스 )
- 아래 예제에서 lazy 키워드를 붙인 변수 보세요!
123456789101112131415161718class DataImporter {var filename = "data.txt"}class DataManager {lazy var importer = DataImporter() // DataImporter 의 인스턴스( 참조정보 )가 lazy var importer 에 저장됨.var data = [String]()}let manager = DataManager()// DataManager 클래스의 인스턴스가 생성될 때 클래스의 모든 요소들이 초기화 된다.// 하지만 lazy 키워드가 붙은 importer 는 DataImporter 의 인스턴스를 생성하지 않고 nil로 초기화 한다.manager.data.append("Some data")manager.data.append("Some more data")print(manager.importer.filename)// importer 가 호출되고 나서야 비로소 importer는 DataImporter 의 인스턴스를 생성한다.cs - 그럼 lazy 키워드 붙은 변수는 초기화 된후, 호출되기 전에는 어떤 상태인가? ( x-code debug 같이 첨부하겠습니다. )
importer 값이 DataImporter의 인스턴스 정보가 아닌, nil 을 가지고 있는 상태 => 호출하기 전에는 nil 로 초기화 된 상태네요^^
- 연산 프로퍼티 : get, set 키워드 : 실제로 값을 저장하는게 아니라 기존 값들로 연산된 값을 자동으로 제공하는 프로퍼티 ( 편리한거죠. )
- 예를 들면서 설명하겠습니다!
- 아래 예제에는 연산 프로퍼티의 사용법과 set 키워드에서 매개변수를 어떻게 생략할 수 있는지를 포함합니다.
123456789101112131415161718192021222324252627282930313233343536373839struct Point {var x = 0.0, y = 0.0}struct Size {var width = 0.0, height = 0.0}struct Rect {var origin = Point() // 원점var size = Size() // 크기var center: Point { // 중심점을 구하는 연산 프로퍼티get { // 저장된 값을 읽어올 때 사용하는 getlet centerX = origin.x + (size.width / 2)let centerY = origin.y + (size.height / 2)return Point(x: centerX, y: centerY)}set(newCenter) {// center 프로퍼티에 새로운 값을 대입하면 origin.x , y 를 자동으로 변경시켜 준다.origin.x = newCenter.x - (size.width / 2)origin.y = newCenter.y - (size.height / 2)}// (newCenter) 부분을 생략할 수 있다. 생략한다면 default 값 ( 기본 설정값 )은 'newValue' 이다.// 생략해서 작성하면 아래와 같다./*set {origin.x = newValue.x - (size.width / 2)origin.y = newValue.y - (size.height / 2)}*/}}}var square = Rect(origin: Point(x: 0.0, y: 0.0), // Rect 구조체 초기화 된 인스턴스 square 에 저장.size: Size(width: 10.0, height: 10.0))let initialSquareCenter = square.center // 연산프로퍼티 center 호출. ( get )print(initialSquareCenter) // center 는 현재 Point(x: 5.0, y: 5.0)square.center = Point(x: 15.0, y: 15.0) // center 를 설정해 준다면 ( set )print("square.origin is now at (\(square.origin.x), \(square.origin.y))")// center 를 15, 15 로 설정하고, width, height 는 모두 10 이므로 origin.x, y 는 10, 10 이 된다.cs - 읽기 전용 ( Read - Only ) : get 키워드도 생략 가능
1234567891011struct Cuboid {var width = 0.0, height = 0.0, depth = 0.0var volume: Double { // 읽기 전용인 연산프로퍼티 : get 키워드도 붙일 필요가 없다.return width * height * depth}}let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")// Prints "the volume of fourByFiveByTwo is 40.0"cs - 프로퍼티 옵저버 : willSet , didSet 키워드 : 프로퍼티 값의 변화를 감지하고 적당할 때 반응할 수 있는 기능.
- 프로퍼티의 값이 같은 값으로 저장되더라도, 저장되는 행위가 수행되면 무조건 프로퍼티 옵저버 실행된다. => 기준점이 '저장' 인 것.
- 저장 프로퍼티 에서 사용 가능하고, lazy 키워드가 붙은 프로퍼티는 불가. ( 연산프로퍼티의 set 과 같은 기능을 수행하기 때문에 연산프로퍼티 에는 필요가 없쥬? )
- willSet 키워드가 붙은 블록{} : 값이 새로 저장되기 전에 호출된다. ( '저장' 이 기준이라고 위에 설명했쥬? )
- didSet 키워드가 붙은 블록{} : 값이 새로 저장된 후에 호출된다.
- 예를 들어 설명함!
123456789101112131415161718192021222324class StepCounter {var totalSteps: Int = 0 { // 프로퍼티 옵저버 사용할 시 let 이 아닌 var 사용willSet(newTotalSteps) {// 프로퍼티 옵저버 willSet : 새로운 값이 저장되기 전에// 매개 변수가 default 가 아닌 ewTotalSteps 로 설정되었다.// default 면 newValue 가 매개변수 로 자동 설정된다.print("About to set totalSteps to \(newTotalSteps)")}didSet {// 프로퍼티 옵저버 didSet// 매개변수가 default 이므로 oldValue 로 자동 설정된다.if totalSteps > oldValue { // default 값인 oldValue 사용한 코드.print("Added \(totalSteps - oldValue) steps")}}}}let stepCounter = StepCounter()stepCounter.totalSteps = 200// About to set totalSteps to 200// Added 200 stepsstepCounter.totalSteps = 360// About to set totalSteps to 360// Added 160 stepscs - 타입 프로퍼티 : 타입 프로퍼티는 이 프로퍼티를 굳이 써야할 이유를 아직 명확히 경험적으로? 체득하지 못해서 .. ( 쓸 일이 없다는 말.. ) 깨달음이 올 때(?) 정리하겠습니다!
- 특정 타입이라 하면, 구조체, 클래스, 열거형 등을 정희하면, 그것이 여기서 말하는 타입이다. someClass 라는 구조체를 정의하고 그 구조체의 인스턴스를 생성하면, someClass 라는 타입의 인스턴스인 것. 그 타입의 여러 가지 생성된 각각의 인스턴스의 프로퍼티가 아니라, 그 타입 자체에 속한 프로퍼티를 정의할 수 있다.
- 저는 뭐.. 이런게 있다 는 정도로 넘어갑니다~
'스위프트: Swift > 스위프트: 언어자체: 문법' 카테고리의 다른 글
댓글