[Swift] 프로퍼티와 메소드에 대해 알아보자!

zooneon·2020년 11월 6일
0

Swift 기본 문법

목록 보기
4/14

본 내용은 '스위프트 프로그래밍' 책을 학습한 후 이를 바탕으로 작성한 글입니다.

프로퍼티와 메소드

프로퍼티는 클래스, 구조체 또는 열거형 등에 관련된 값을 뜻하고 메서드는 특정 타입에 관련된 함수를 뜻한다.

프로퍼티

프로퍼티는 크게 저장 프로퍼티, 연산 프로퍼티, 타입 프로퍼티로 나눌 수 있다.

저장 프로퍼티

  • 클래스 또는 구조체의 인스턴스와 연관된 값을 저장하는 가장 단순한 개념의 프로퍼티
  • 저장 프로퍼티를 정의할 때 프로퍼티 기본값과 초깃값을 지정해줄 수 있다.
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")

연산 프로퍼티

  • 연산 프로퍼티는 특정 상태에 따른 값을 연산하는 프로퍼티이다.
  • 인스턴스 내/외부의 값을 연산하여 적절한 값을 돌려주는 접근자의 역할이나 은닉화된 내부의 프로퍼티 값을 간접적으로 설정하는 설정자의 역할을 할 수도 있다.
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

메서드

메서드는 특정 타입에 관련된 함수를 말한다. 스위프트에서는 구조체와 열거형도 메서드를 가질 수 있다.

인스턴스 메서드

  • 인스턴스 메서드는 특정 타입의 인스턴스에 속한 함수를 뜻한다.
  • 인스턴스 내부의 프로퍼티 값을 변경하거나 특정 연산 결과를 반환하는 등 인스턴스와 관련된 기능을 실행한다.
  • 인스턴스 메서드는 함수와 달리 특정 타입 내부에 구현한다.
  • 구조체나 열거형 등은 값 타입이므로 메서드 앞에 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
profile
블로그 이전했습니다. https://blog.zooneon.dev

0개의 댓글