Swift Property
* 스스로 공부 및 정리를 위해 The Swift Language Guide을 요약 및 정리 한 내용입니다.
프로퍼티(Property)
- 클래스, 구조체, 열거형과 관련된 값입니다.
- 저장 프로퍼티와 계산된 프로퍼티가 있습니다.
- 저장 프로퍼티는 말그대로 값을 저장하고 있는 프로퍼티입니다.
- 계산된 프로퍼티는 값을 저장하지 않고 특정하게 계산한 값을 반환해 주는 프로퍼티입니다.
- 계산된 프로퍼티는 모두에서 사용가능하지만, 저장프로퍼티는 클래스와 구조체에서만 사용 가능합니다.
저장 프로퍼티(Stored Property)
- 단순히 값을 저장하고 있는 프로퍼티입니다.
- let 이나 var 키워드를 이용해서 선언해 사용할수 있습니다.
상수구조체 인스턴스의 저장 프로퍼티(Stored Property of Constant Structure Instance)
- 구조체를 상수로 선언하면 그 구조체 인스턴스의 프로퍼티를 변경할수 없습니다.
- 클래스의 경우는 참조타입이기 때문에 let으로 상수선언해도 값 변경 가능하다.
struct StructName {
var width = 1
var height = 1
}
let StructInstance = StructName(width: 10, height: 10)
StructInstance.width = 100
//에러발생
//StructName(width: 5, height: 5)으로 해봤자 값복사기 때문에 의미없다. 결국 선언값인 1,1이다
class ClassName{
var wid = 10
var hei = 10
}
let ClassInstance = ClassName()
ClassInstance.wid = 100
print(ClassInstance.wid)
지연 저장 프로퍼티(Lazy Stored Property)
- 지연 저장 프로퍼티는 값이 처음으로 사용 되기 전에는 계싼되지 않는 프로퍼티입니다.
- 프로퍼티 앞에 lazy를 선언하면 됩니다.
- 반드시 변수는 var로 선언되어야합니다( lazy var)
- 특정 요소에 의존적이어서 그 요소가 끝나기 전에 적절한 값을 알지 못하는 경우에 유용합니다.
- 자동클로저의 프로퍼티 버전같은 느낌과 비슷합니다.
- 고로, 복잡한 계산이나 부하기 많이 걸리는 작업에 이용하면 실제 사용되기 전까지는 실행되지 않아서 부하나 복잡한 계산을 피할수 있습니다.
- 전역변수로 선언시 오류가 생깁니다. 지역변수에서 사용해주어야합니다.
class DataSave{
var Animal = ["Dog", "Cat"]
}
class Date{
lazy var datas = DataSave()
}
print(DataSave().Animal)
let manage = Date()
manage.datas.Animal.append("Bird")
print(DataSave().Animal) //Bird가 추가되지않았습니다.
print(manage.datas.Animal) //Bird가 추가되어있습니다.
저장 프로퍼티와 인스턴스 변수(Stord Property and Instance Variable)
- Swift는 프로퍼티의 이름,타입,메모리 관리등의 모든 정보를 프로퍼티를 선언하는 한곳에 정의하게 됩니다.
계산된 프로퍼티(Computed Property)
- 클래스, 구조체, 열거형은 계산된 프로퍼티를 사용할수 있습니다.
- 실제값을 저장하는 것이 아니라 getter와 setter를 제공해 값을 탐색하고 간접적으로 다른 프로퍼티 값을 설정할수 있습니다.
- C#에서도 getter, setter를 데이터 접근보호를 공부하면서 배우면서도 힘들었던 부분이었던게 기억납니다.
- C#을 공부할때는 읽기, 쓰기 로 이해가 잘안되서 단순히 외워보기까지했습니다.
- Rect는 딱히 어떤값을 가지고있지는 않습니다. 단지 Get과 Set을 통해 가지고 있는 연산식을 통해 프로퍼티를 구할뿐입니다.
- square을 선언할때 받은 값으로 Get함수에서 centerX,centerY가 (5,5)라 연산하고, 사이즈가10*10를 받아왔을뿐입니다.
- square.center를 통해 Set함수를 통해 newCenterX,newCenterYrㅏ(10,10)에 받아온 Get에서 가진 사이즈가 10*10으로 기억하고 연산할뿐입니다.
struct 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{
let centerX = origin.x + (size.width/2)
let centerY = origin.y + (size.height/2)
return Point(x: centerX, y: centerY)
}
set(newCenter){
origin.x = newCenter.x - (size.width/2)
origin.y = newCenter.y - (size.height/2)
}
}
}
var square = Rect(origin: Point(x: 0.0,y: 0.0),
size: Size(width: 10.0,height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0,y: 15.0)
print("Square.origin is now at (\(square.origin.x), \(square.origin.y))")
Setter 선언의 간략한 표현 (Shorthand Setter Declaration)
- set(newCenter)라고 명시하지않고, (newCenter)를 적어주지 않아도 newValue로 사용가능합니다.
읽기 전용 계산된 프로퍼티 (Read-Only Computed Property)
- getter만 있고 setter를 제공하지 않으면 읽기전용 계산된 프로퍼티라고 합니다.
- 반드시 반환값을 제공하지만 다른값을 지정할수 없는 프로퍼티입니다.
- getter로 값을 읽어 내부에 맞게 연산만해주는 것 뿐입니다.
프로퍼티 옵저버(Property Observe)
- 새 값이 설정(set) 될 때마다 이 이벤트를 감지 할수 있는 옵저버입니다.
- 이벤트가 발생하면 감지하기에 값이 변동이 없어도 호출됩니다.
- 지연저장 프로퍼티에서는 사용할수 없습니다.
- 서브클래스의 프로퍼티에 옵저버를 정의하는 것도 가능합니다.
- setter에서 값의 변화를 감지 할수 있기 때문에 따로 옵저버를 정의할 필요는 없습니다.
- 2가지 옵저버를 제공합니다.
- willSet : 값이 저장되기 바로 직전에 호출됨
- didSet : 새값이 저장되고 난 직후에 호출됨
- willSet에서는 새값의 파라미터명을 지정할수 있는데, 지정하지 않으면 기본값으로 newValue를 사용합니다
- didSet에서는 파뀌기 전의 값의 파라미터 명을 지정할수 있는데, 지정하지 않으면 기본값으로 oldValue를 사용합니다.
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet{
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 300
전역변수와 지역변수(Global and Local Variable)
- 옵저버 기능은 전역변수, 지역변수 모두에서 이용 가능합니다.
- 전역변수란 함수, 메소드, 클로저 혹은 타입 컨텍스트 밖에 정의된 변수입니다.
- 지역변수는 그안에 선언된 변수를 말합니다(특정 Func에서 선언된 변수 등등)
- 전역 상수와 변수는 지연저장 프로퍼티와 같이 지연계산 됩니다. 따라서 lazy 선언해줄 필요는 없습니다.
타입프로퍼티(Type Property)
- 인스턴스 프로퍼티는 특정 인스턴스에 속한 프로퍼티를 말합니다.
- 새로운 인스턴스가 생성될 때마다 새로운 프로퍼티도 같이 생성됩니다.
- 타입 프로퍼티는 특정 타입에 속한 프로퍼티로 그타입에 해당하는 단 하나의 프로퍼티만 생성됩니다.
- 특정 타입의 모든 인스턴스에 공통으로 사용되는 값을 정의할 때 유용합니다.
- 인스턴스 프로퍼티와는 다르게 항상 초기값을 지정해서 사용해야합니다. 타입자체에 초기자(Initializer)가 없어 초기화 할 곳이 없습니다.
타입 프로퍼티 구문(Type Property Syntax)
- static 키워드를 사용해서 선언합니다.
- class로 선언된 프로퍼티는 서브클래스에서 오버라이드 가능합니다.
- class에 선언하는게 아니라 프로퍼티인만큼 내부에서 프로퍼티 선언할때 프로퍼티에 선언해주야합니다
- 구조체, 열거형, 클래스 타입에서 사용가능합니다.
- 타입 프로퍼티를 쓰는 이유는 다른곳에 할당해서 값이 변동해도, 타입프로퍼티는 하나이기 때문에 직접 접근하지않으면 변경되지 않기 때문에 특정 기준점등으로 사용하기 좋습니다. ex) 특정 상황의 최대값 or 최소값
struct StructureName{
static var width
static var height
}
타입 프로퍼티의 접근과 설정 (Qurrying and Setting Type Property)
- Dot연산자로 프로퍼티의 값을 가져오고 할당 할수 있습니다.
struct StructureName{
static var width = 10
static var height = 10
}
StructureName.width = 100
print(StructureName.width)