property 는 속성이라면 method 는 행동이다.
list.push(1) 처럼 괄호로 끝나면 method, list.count 처럼 없으면 property 라고 할 수 있다.
구조체와 클래스에서는 var 또는 let 을 정의하여 내부적인 값을 저장할 수 있습니다. 이렇게 구조체와 클래스 내부에서 정의된 var 또는 let 을 프로퍼티(Property), 또는 속성이라고 합니다. 함수를 정의하여 특정 기능을 정의할 수 있는데 이를 메서드(Method)라고 합니다.
프로퍼티(Property)와 메서드(Method)의 차이는 구조체나 클래스 내부에 정의된다는 것만 차이가 있을 뿐, 일반 변수/상수/함수를 정의하는 것과 문법적으로 동일합니다.
다음은 구조체와 클래스를 정의하고 여기에 프로퍼티와 메서드를 추가하는 예제 코드입니다.
struct Resolution {
var width = 0
var height = 0
func desc() -> String {
return "Resolution 구조체"
}
}
class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
func desc() -> String {
return "VideoMode 클래스"
}
}
프로퍼티
Resolution이라는 이름의 구조체와 VideoMode라는 이름의 클래스를 선언하였습니다. Resolution 구조체에는 width 와 height 라는 두 개의 저장 프로퍼티가 있습니다. 저장 프로퍼티란 특정 값을 저장하기 위해 클래스나 구조체 내부에 정의된 변수(var) 또는 상수(let)을 의미합니다. 두 프로퍼티는 선언될 때 초기값으로 0이 대입되었으므로 타입 추론 규칙에 의해 Int 타입의 데이터 형식으로 추론됩니다.
반면 VideoMode 클래스는 세 개의 저장 프로퍼티가 정의되어 있습니다.
메서드
구조체와 클래스에는 desc라는 이름의 메서드가 하나씩 작성되어 있습니다. 이 메서드의 역할은 각각의 프로퍼티에 대해 설명하는 문자열을 반환하는 것입니다. 위에서 확인할 수 있는것처럼 메서드는 함수의 형태를 띠고 있으며 몇 가지 차이점을 제외하면 함수와 거의 같습니다. 메서드는 단지 클래스나 구조체 내부에서 작성된 함수인 셈입니다.
더 나아가 메서드와 함수의 차이를 확실히 정리하자면 함수는 전역이던 지역이던 독립된 기능을 수행하는 단위며 메서드는 클래스, 구조체, 열거형에 포함되어 있는 "함수"를 메서드라고 부른다. 메서드를 다른말로 "클래스 함수"라고도 한다.
func someFunction{
//some code
}
class someClass{
func someMethod{
//some code
}
}
프로퍼티
프로퍼티는 크게 저장 프로퍼티, 연산 프로퍼티, 타입 프로퍼티라고 나눌 수 있습니다.
저장 프로퍼티
- 클래스 또는 구조체의 인스턴스나 연관된 값을 저장하는 가장 단순한 개념의 프로퍼티
- 상수(let) 및 변수(var)를 사용해서 정의 가능
- 저장 프로퍼티를 정의할 때 프로퍼티 기본값과 초깃값을 지정해줄 수 있다.
struct Person {
var name: String
var age: Int
}
let zooneon: Person = Person(name: "zooneon", age: 100)
class Book {
var title: String
let author: String
init(title: String, author: String) {
self.title = title
self.author = author
}
}
let favoriteBook: Book = Book(title: "Harry Potter", author: "Joan K. Rowling")
지연 저장 프로퍼티
- 지연 저장 프로퍼티는 호출이 있어야 값을 초기화하며, lazy 키워드를 사용한다.
- 상수는 인스턴스가 완전히 생성되기 전에 초기화해야 하므로 지연 저장 프로퍼티와는 맞지 않다.
- 지연 저장 프로퍼티는 var 키워드를 사용하여 변수로 정의한다
- 지연 저장 프로퍼티로 불필요한 성능저하나 공간 낭비를 줄일 수 있다.
struct Favorite {
var food: String = "sushi"
var music: String = "k-pop"
}
class Person {
lazy var favorite: Favorite = Favorite()
let name: String
init(name: String) {
self.name = name
}
}
let zooneonInfo: Person = Person(name: "zooneon")
print(zooneonInfo.favorite) //Favorite(food: "sushi", music: "k-pop")
연산 프로퍼티
- 연산 프로퍼티는 특정 상태에 따른 값을 연산하는 프로퍼티다
- 인스턴스 내/외부의 값을 연산하여 적절한 값을 돌려주는 접근자 get 의 역할이나 은닉화된 내부의 프로퍼티 값을 간접적으로 설정하는 설정자 set 의 역할을 할 수도 있다
struct Person {
var name: String
var age: Int
//연산 프로퍼티
var personInfo: Person {
//접근자
get {
return Person(name: name, age: age)
}
//설정자
set(info) {
name = info.name
age = info.age
}
}
}
var zooneonInfo: Person = Person(name: "zooneon", age: 100)
print(zooneonInfo) //Person(name: "zooneon", age: 100)
print(zooneonInfo.personInfo) //Person(name: "zooneon", age: 100)
zooneonInfo.personInfo = Person(name: "Junwon", age: 24)
print(zooneonInfo) //Person(name: "Junwon", age: 24)
프로퍼티 옵저버
- 프로퍼티 옵저버를 사용하면 프로퍼티의 값이 변경됨에 따라 적절한 작업을 취할 수 있다.
- 프로퍼티 옵저버는 프로퍼티의 값이 새로 할당될 때마다 호출한다.
- 변경되는 값이 현재의 값과 같더라도 호출한다.
- 프로퍼티 옵저버는 프로퍼티를 재정의해 상속받은 저장 프로퍼티 또는 연산 프로퍼티에도 적용할 수 있다.
- 연산 프로퍼티는 상속받았을 때만 프로퍼티 재정의를 통해 프로퍼티 옵저버를 사용한다.
- 프로퍼티 옵저버에는 프로퍼티의 값이 변경되기 직전에 호출하는 willSet메서드와 프로퍼티의 값이 변경된 직후에 호출하는 didSet메서드가 있다.
- willSet 메서드에 전달되는 전달인자는 프로퍼티가 변경될 값이고, didSet 메서드에 전달되는 전달인자는 프로퍼티가 변경되기 전의 값이다.
- 매개변수의 이름을 따로 저장하지 않으면 willSet메서드에는 newValue, didSet메서드에는 oldValue라는 매개변수 이름이 자동 지정된다.
class Account {
var credit: Int = 0 {
willSet {
print("잔액이 \(credit)원에서 \(newValue)원으로 변경될 예정입니다.")
}
didSet {
print("잔액이 \(oldValue)원에서 \(credit)원으로 변경되었습니다.")
}
}
}
let myAccount: Account = Account()
//잔액이 0원에서 1000원으로 변경될 예정입니다.
myAccount.credit = 1000
//잔액이 0원에서 1000원으로 변경되었습니다.
타입 프로퍼티
- 각각의 인스턴스가 아닌 타입 자체에 속하는 프로퍼티를 타입 프로퍼티라고 한다.
- 타입 프로퍼티는 타입 자체에 영향을 미치는 프로퍼티이다.
- 인스턴스의 생성 여부와 상관없이 타입 프로퍼티의 값은 하나이다.
- 타입의 모든 인스턴스가 공통으로 사용하는 값, 모든 인스턴스에서 공용으로 접근하고 값을 변경할 수 있는 변수 등을 정의할 때 유용하다.
- 저장 타입 프로퍼티는 변수 또는 상수로 선언할 수 있으며, 연산 타입 프로퍼티는 변수로만 선언할 수 있다.
- 저장 타입 프로퍼티는 반드시 초깃값을 설정해야 하며 지연 연산된다.
class AClass {
static var typeProperty: Int = 0
var instanceProperty: Int = 0 {
didSet {
Self.typeProperty = instanceProperty + 100
}
}
static var typeComputedProperty: Int {
get {
return typeProperty
}
set {
typeProperty = newValue
}
}
}
AClass.typeProperty = 123
let classInstance: AClass = AClass()
classInstance.instanceProperty = 100
print(AClass.typeProperty) //200
print(AClass.typeComputedProperty) //200
메서드
메서드는 특정 타입에 관련된 함수를 말한다. Swift 에서는 구조체와 열거형도 메서드를 가질 수 있다.
인스턴스 메서드
- 인스턴스 메서드는 특정 타입의 인스턴스에 속한 함수를 뜻한다
- 인스턴스 내부의 프로퍼티 값을 변경하거나 특정 연산 결과를 반환하는 등 인스턴스와 관련된 기능을 실행한다.
- 인스턴스 메서드는 함수와 달리 특정 타입 내부에 구현한다.
- 구조체나 열거형 등은 값 타입이므로 메서드 앞에 mutating 키워드를 붙여 해당 메서드가 인스턴스 내부의 값을 변경한다는 것을 명시해야한다.
struct LevelStruct {
var level: Int = 0 {
didSet {
print("Level \(level)")
}
}
mutating func levelUp() {
print("Level Up")
level += 1
}
mutating func levelDown() {
print("Level Down")
level -= 1
if level < 0 {
reset()
}
}
mutating func jumpLevel(to: Int) {
print("Jump to \(to)")
level = to
}
mutating func reset() {
print("Reset")
level = 0
}
}
var levelStructInstance: LevelStruct = LevelStruct()
levelStructInstance.levelUp() //Level Up
//Level 1
levelStructInstance.levelDown() //Level Down
//Level 0
levelStructInstance.levelDown() //Level Down
//Level -1
//Reset
//Level 0
levelStructInstance.jumpLevel(to: 3) //Jump to 3
//Level 3
self 프로퍼티
- 모든 인스턴스는 암시적으로 생성된 self프로퍼티를 갖는다.
- self프로퍼티는 자바의 this와 비슷하게 인스턴스 자기 자신을 가리키는 프로퍼티이다.
- self프로퍼티는 인스턴스를 더 명확히 지칭하고 싶을 때 사용한다.
callAsFunction
- 특정 타입의 인스턴스를 문법적으로 함수를 사용하는 것처럼 보이게 할 수 있다.
- 인스턴스를 함수처럼 호출할 수 있도록 하려면 callAsFunction이라는 메서드를 구현하면 된다.
- 매개변수와 반환 타입만 다르면 개수에 제한 없이 원하는만큼 만들 수 있다.
struct Person {
var name: String = "zooneon"
func callAsFunction() {
print("Hi")
}
func callAsFunction(food: String) {
print("\(food)를 좋아합니다.")
}
func callAsFunction(hometown: String, age: Int) {
print("고향은 \(hometown)이며 나이는 \(age)살 입니다.")
}
}
var zooneon: Person = Person()
zooneon.callAsFunction() //Hi
zooneon() //Hi
zooneon.callAsFunction(food: "초밥") //초밥를 좋아합니다.
zooneon(food: "초밥") //초밥를 좋아합니다.
zooneon.callAsFunction(hometown: "서울", age: 24) //고향은 서울이며 나이는 24살 입니다.
zooneon(hometown: "서울", age: 24) //고향은 서울이며 나이는 24살 입니다.
타입 메서드
- 타입 자체에 호출이 가능한 메서드를 타입 메서드라고 한다.
- 클래스의 타입 메서드는 static키워드와 class키워드를 사용할 수 있다.
- static으로 정의하면 상속 후 메서드 재정의가 불가능하고 class로 정의하면 상속 후 메서드 재정의가 가능하다.
- 타입 메서드는 self프로퍼티가 타입 그 자체를 가르킨다.
class AClass {
static func staticTypeMethod() {
print("AClass staticTypeMethod")
}
class func classTypeMethod() {
print("AClass classTypeMethod")
}
}
class BClass: AClass {
/*
override static func staticTypeMethod() {
//오류 발생
}
*/
override class func classTypeMethod() {
print("BClass classTypeMethod")
}
}
AClass.staticTypeMethod() //AClass staticTypeMethod
AClass.classTypeMethod() //AClass staticTypeMethod
BClass.staticTypeMethod() //AClass staticTypeMethod
BClass.classTypeMethod() //BClass classTypeMethod
'SwiftUI' 카테고리의 다른 글
wrappedValue, projectedValue (0) | 2023.11.10 |
---|---|
property wrapper (0) | 2023.11.10 |
Environment (0) | 2023.11.08 |
URL (0) | 2023.11.08 |
Files (0) | 2023.11.08 |