[Swift] 구조체와 클래스 - 프로퍼티

민니·2022년 7월 4일
0

Swift 문법

목록 보기
8/17

프로퍼티 ❓

  • 값을 저장하기 위한 목적으로,
    클래스와 구조체 내에서 정의된 변수나 상수
  • 정확한 역할을 값을 제공하는 것
  • 프로퍼티 중 일부는 값을 저장하지는 않지만 값을 제공하기도 함

값을 저장하지 않는데 어떻게 제공을 한다는 거지? 🤔
더 알아보자!



프로퍼티 종류

  • 저장 여부에 따라
    저장 프로퍼티, 연산 프로퍼티
  • 클래스나 구조체에 대한 소속 여부에 따라
    인스턴스 프로퍼티, 타입 프로퍼티


저장 프로퍼티

  • 클래스나 구조체 내에서 선언된 변수나 상수
  • 클래스에서 프로퍼티 선언 시
    📚 초기값이 할당되지 않은 저장 프로퍼티는 반드시 옵셔널 타입으로 선언
    📚 프로퍼티에 값이 비어 있으면 인스턴스를 생성할 대 무조건 nil로 초기화하므로
    📚 초기화 예시
//error
class User {
	var name: String
}

//초기화 구문 작성, 그 안에서 초기화 할당
class User {
	var name: String
    
    //인스턴스가 생성될 때 실행된다
    init() {
    	self.name = ""
    }
}

//프로퍼티를 옵셔널 타입으로 바꿔주기
class User {
	var name: String?
}
//or 묵시널 옵셔널 해제 타입 -> 프로퍼티 값이 nil이 되지 않을 자신이 있다면
class User {
	var name: String!
}
  • 구조체에서 프로퍼티 선언 시
    📚 초기값을 할당하지 않고 선언만 하더라도, 옵셔널 타입으로 지정해 줄 필요 없음 -> 멤버와이즈 초기화 구문을 이용하면 되므로


저장 프로퍼티 분류

  • 변수 저장 프로퍼티(var 키워드 정의) : 값 수정 o
  • 상수 저장 프로퍼티(let 키워드 정의) : 최초 할당된 값이 유지

📚 Example

//고정 길이 범위 구조체
struct FixedLengthRange {
	var startValue: Int //시작값
    let length: Int //값의 범위
}

//가변 길이 범위 구조체
struct FlexibleLengthRange {
	let startValue: Int //시작값
    var length: Int //값의 범위
}

var rangeOfFixedIntegers = FixedLengthRange(startValue: 0, length: 3)
rangeOfFixedIntegers.startValue = 4 
rangeOfFixedIntegers.length = 5 //error

var rangeOfFlexibleIntegers = FlexibleLengthRange(startValue: 0, length: 3)
rangeOfFlexibleIntegers.length = 5
rangeOfFlexibleIntegers.startValue = 3 //error
  • 구조체 인스턴스를 변수에 할당할 경우
    ㄴ 구조체 내에서 변수로 정의한 프로퍼티는 값 수정 가능
  • 구조체 인스턴스를 상수에 할당할 경우
    ㄴ 구조체 내에서 변수로 정의한 프로퍼티일지라도 값 수정 불가능
  • 클래스는 인스턴스를 상수에 할당하더라도, 변수 저장 프로퍼티는 수정 가능함!

📚 Example

var variablesOfInstance = FixedLengthRange(startValue: 3, length: 4)
variablesOfInstance.startValue = 0 //수정 가능

let constantsOfInstance = FixedLengthRange(startValue: 3, length: 4)
constantsOfInstance.startValue = 0 //error 수정 불가능


지연 저장 프로퍼티 ❓

  • 프로퍼티는 일반적으로 인스턴스가 생성될 때 함께 초기화
  • lazy 키워드가 붙으면 저장 프로퍼티의 초기화를 지연시킴
  • 프로퍼티가 호출되는 순간에 초기화됨
    ❗️ 호출되기 전에는 선언만 된 상태로 대기하다가, 실제로 호출되는 시점에서 초기화가 이루어지는 저장 프로퍼티 ❗️

📚 Example

class Oncreate {
	init() {
    	print("OnCreate!!")
    }
}

class LazyText {
	var base = 0
    lazy var late = OnCreate()
    
    init() {
    	print("Lazy Test")
    }
}

let lz = LazyTest() 
//출력: Lazy Test

lz.late
//출력: OnCreate!!

📚 지연 저장 프로퍼티에 대입된 인스턴스는 프로퍼티가 처음 호출되는 시점에서 생성
📚 두 번째 호출부터는 처음 초기화된 값을 사용, 다시 초기화 ❌



연산 프로퍼티 ❓

  • 필요한 값을 제공하긴 하지만......
  • 실제 값을 저장했다가 반환하진 않고, 다른 프로퍼티의 값을 연산처리하여 간접적으로 값을 제공
  • get 구문: 프로퍼티의 값을 참조 (return 키워드 사용)
  • set 구문: 연산 프로퍼티에 값을 할당하거나 변경하고자 할 때 실행
  • 다른 프로퍼티에 의존적이거나, 특정 연산을 통해 얻을 수 있는 값을 정의할 때 사용

정의 형식

class/struct/enum 객체명 {
	...
    var 프로퍼티명: 타입 {
    	get {
        	//필요한 연산 과정
            return 반환값
        }
        set(매개변수명) {
        	//필요한 연산 구문
        }
   	}
}
  • Example - 사각형의 중심 좌표 구하기
struct Rect {
    //사각형 위치한 기준 좌표
    var originX: Double = 0.0
    var originY: Double = 0.0
    
    //가로 세로 길이
    var sizeWidth: Double = 0.0
    var sizeHeight: Double = 0.0
    
    //사각형의 X 좌표 중심
    var centerX: Double {
        get {
            return self.originX + (sizeWidth/2)
        }
        //입력도니 인자값을 이용하여 기준 좌표 프로퍼티의 값을 변경
        set(newCenterX) {
            self.originX = newCenterX - (sizeWidth/2)
        }
    }
    
    //사각형 Y 좌표 중심
    var centerY: Double {
        get {
            return self.originY + (sizeHeight/2)
        }
        set(newCenterY) {
            self.originY = newCenterY - (sizeHeight/2)
        }
    }
}

var square = Rect(originX: 0.0, originY: 0.0, sizeWidth: 10.0, sizeHeight: 10.0)
print("square.centerX = \(square.centerX), square.centerY = \(square.centerY)")
//square.centerX = 5.0, square.centerY = 5.0

📚 연산 프로퍼티에 값을 할당하면 set 구문에 정의된 구문 실행
📚 프로퍼티에 할당된 값은 set 다음에 오는 인자값으로 전달
📚 매개변수명이 생략된다면 newValue 인자명 사용
📚 연산 프로퍼티에 할당할 값이 앞에서 이미 정의되어 있으므로 매개변수 타입 정의 생략 가능


연산 프로퍼티 특징

  • 읽기 전용 프로퍼티(read-only 프로퍼티): set 구문만 제거하면, 값을 읽기만 할 뿐 수정은 불가능
  • 연산 프로퍼티를 보면서 계속 들었던 의문... 그냥 메서드로 표현하면 안 되나? 🤔 근데 진짜 사실 메서드로 표현할 수 있다고 함.
  • set 연산만은 ❌


프로퍼티 옵저버 ❓

  • 특정 프로퍼티를 계속 관찰하고 있다가, 프로퍼티의 값이 변경되면 알아차리고 반응
  • 프로퍼티의 값이 설정되면 호출
  • willSet: 프로퍼티의 값이 변경되기 직전에 호출되는 옵저버
  • didSet: 프로퍼티의 값이 변경된 직후에 호출되는 옵저버
  • 한쪽 옵저버만 선택적으로 구현 가능

willSet

  • 프로퍼티의 값이 변경되기 직전에 호출되는 옵저버
  • 프로퍼티에 대입되는 값이 매개상수 형식으로 전달
  • 매개상수에 이름 부여하지 않으면 newValue 이름으로 전달
  • 따라서, 프로퍼티 값이 변경되기 전에 처리해야 할 뭔가가 있다면 willSet 이용하여 처리
  • 정의 형식 ([]는 생략 가능)
var <프로퍼티명>: <타입> [ = <초기값> ] {
	willSet[(<인자명>)] {
    	//프로퍼티 값이 변경되기 전에 실행할 내용
    }
}

didSet

  • 프로퍼티에 값이 할당된 직후에 호출
  • 기존에 저장되어 있던 값이 매개상수 형태로 전달
  • 매개상수에 이름 부여하지 않으면 oldValue 이름으로 전달
  • 정의 형식 ([]는 생략 가능)
var <프로퍼티명>: <타입> [ = <초기값> ] {
	didSet[(<인자명>)] {
    	//프로퍼티 값이 변경되기 전에 실행할 내용
    }
}

📚 Example

struct Job {
    var income: Int = 0 {
        willSet(newIncome) {
            print("이번 달 월급은 \(newIncome)원입니다.")
        }
        didSet {
            print("저번 달 월급은 \(oldValue)원입니다.")
        }
    }
}

var job = Job(income: 500000)
job.income = 1000000

//이번 달 월급은 1000000원입니다.
//저번 달 월급은 500000원입니다.


타입 프로퍼티 ❓

  • 인스턴스 프로퍼티: 프로퍼티가 인스턴스에 관련된 값을 저장하고 다루는 프로퍼티
  • 타입 프로퍼티: 인스턴스에 관련된 값이 아닌 클래스나 구조체와 열거형 같은 객체 자체에 관련된 값을 저장하는 프로퍼티
  • 인스턴스를 생성하지 않고 클래스나 구조체 자체에 저장
  • 저장된 값은 모든 인스턴스가 공통으로 사용 가능
  • 따라서 모든 인스턴스들이 공유해야 하는 값을 정의할 때 유용
  • 사용할 프로퍼티 앞에 static 키워드 추가

정의 형식

  • static 키워드 사용
static let/var 프로퍼티명 = 초기값
  • class 키워드: 클래스의 연산 프로퍼티에 사용 가능
    상속받은 하위 클래스에서 재정의할 수 있음
class let/var 프로퍼티명 : 타입 {
	get {
    	return 반환값
    }
    set {
    }
}
  • 타입 프로퍼티는 인스턴스와 상관없어, 인스턴스 생성 과정에 서 초기값을 할당할 수 없으므로, 반드시 초기값을 할당해야 함

📚 Example

struct Foo {
	static var sFoo = "구조체 타입 프로퍼티값"
    static var cFoo: Int {
    	return 1
    }
}

class Boo {
	static var sFoo = "클래스 타입 프로퍼티값"
    static var cFoo: Int {
    	return 10
    }
    
    class var oFoo: Int {
    	return 100
    }
}

print(Foo.sFoo) //구조체 타입 프로퍼티값
Foo.sFoo = "새로운 값"
print(Foo.sFoo) //새로운 값 
print(Foo.cFoo) //1

print(Boo.sFoo) //클래스 타입 프로퍼티값
Boo.sFoo = "새로운 값"
print(Foo.sFoo) //새로운 값
print(Boo.cFoo) //10

var insFoo = Foo()
print(insFoo.sFoo) //error






출처)
꼼꼼한 재은씨의 스위프트: 문법편

0개의 댓글