본문 바로가기

iOS 프로그래밍/문법

[swift] 문법정리4 (클래스, 상속, 익스텐션)

객체지향 용어 비교

스위프트 클래스 선언하기

class 새로운 클래스 이름: 부모 클래스 {

// 속성(프로퍼티)

// 인스턴스 메서드

// 타입(type) 메서드(클래스 메서드)

}

- "속성" 부분은 클래스 내에 포함되는 변수(var)와 상수(let)를 정의 한다.

- "인스턴스 메서드"는 객체가 호출하는 메소드를 정의한다.

- "타입 메서드" 는 클래스가 호출하는 메서드를 정의한다.

인스턴스 선언하고 초기화하기, 해제하기

- 위의 클래스를 가지고 어떠한 일을 하기 위해서는 클래스의 인스턴스를 만드어야 한다.

- 가장 먼저 할 일은 인스턴스가 만들어졌을 때 이 인스턴스의 참조체를 저장할 변수를 선언하는 것

· var 인스턴스명: 클래스명 = 클래스명()

· var 변수명: 자료형 = 초깃값

- 클래스가 생성되는 시점에서 해야할 초기화작업이 있을 경우

→클래스 내에 있는 init 메서드에 위치 시킨다.

ex)

class BankAccount { 

    var accountBalance: Float = 0 

    var accountNumber: Int = 0 

    init(number: Int, balance: Float)

    { 

        accountBalance = balance

        accountNumber = number

    } 

    func displayBalance()  //인스턴스 메서드 

    { 

        print("Number \(accountNumber)") 

        print("Current balance is \(accountBalance)") 

    }

}

var account1 = BankAccount(number: 12312312, balance: 400.54)

// init 메서드 있고 나서는 인스턴스를 생성할 때 초기화 값을 제공해야 함

 

- 그와는 반대로, 클래스 인스턴스가 스위프트 런타임 시스템에 의해 해제되기 전에 수행되어야 할 정리 작업은

클래스의 해제자를 구현하여 수행하게 된다

deinit { //C++의 소멸자

// 필요한 정리 작업을 수행하는 곳

}

메서드 호출하기와 속성 접근하기

- 도트 표기법은 인스턴스 다음에 점(도트, dot)을, 그리고 그 다음에 속성 또는 메서드의 이름을 지정하여 변수나 메서드를 호출한다.

 classInstance.propertyName

 classInstance.instanceMethod()

- 타입 메서드는 클래 인스턴스가 아닌 클래스 타입으로 호출되어야 한다.

 ClassName.typeMethod()

저장된 속성과 계산된 속성

property

- 저장된 속성(stored property)

- 계산된 속성(calculated property) : 속성이 설정되거나 검색되는 시점에서 계산 또는 파생된 값

if) 현재 잔고에 은행 수수료를 뺀 값을 담는 속성 추가

class BankAccount { 

    var accountBalance: Float = 0  //저장된 속성 
    var accountNumber: Int = 0 
    let fees: Float = 25.00      //추가된 저장된 속성 

    var balanceLessFees: Float {   //계산된 속성 
        get {  //이 줄은 생략 가능 
        return accountBalance – fees 
        }      //이 줄은 생략 가능 
    }

    init(number: Int, balance: Float)
    { 
        accountNumber = number 
        ... ..
}

 

- setter가 없으면 get{ }는 생략할 수 있으며 변경 하지 않더라도 var로 선언해야 함

- 세터도 동일한 방식으로 선언하면 입력된 잔고 값에서 수수료를 뺀 값을 설정하게 된다.

var balanceLessFees: Float {

    get {

        return accountBalance - fees

    }

    set(newBalance) {

        accountBalance = newBalance - fees

    }

}

스위프트 self 이용하기

- 객체지향 프로그래밍 언어에 익숙한 프로그래머는 현재 클래스 인스턴스에 속한 메서드나 속성을 가리킬 때 메서드나 속성 앞에 self를 붙이는 습관

- 스위프트 프로그래밍 언어 역시 그렇게 사용하는 self 속성 타입을 제공 하지만 대부분의 경우는 self를 사용할 필요가 없다.

 왜냐하면 self가 속성과 메서드에 대한 디폴트 참조체라고 가정하기 때문이다.

self를 사용해야 하는 상황은

1. property나 메서드를 클로저(closure) 표현식 내에서 참조할 경우

document?.openWithCompletionHandler({(success: Bool) -> Void in
  if success {
      self.ubiquityURL = resultURL //클로저 표현식 내
  } 
}) 

 

2. 함수의 매개변수가 클래스 속성과 동일한 이름을 가질 경우

class MyClass { 
    var myNumber = 10 // property 
    
    func addTen(myNumber: Int) { 
        print(myNumber) // 함수의 매개변수 값을 출력한다 
        print(self.myNumber) // property 값을 출력한다. 10 
    } 
}

 

클래스 이해를 위한 추가 소스들

class Man{
    var age : Int = 1
    var weight : Double = 3.5
    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
    class func cM(){
        print("cM is a class method")
    }
}
var kim : Man = Man()
kim.display()
Man.cM()

 

class Man{

    var age : Int = 1

    var weight : Double = 3.5

    var manAge : Int{
         get{
             return age-1
        } 

        set(USAAge){ 
            age = USAAge + 1 
        }

    }

    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }

    init(age: Int, weight : Double){ 
        self.age = age 
        self.weight = weight 
    }
}

var kim : Man = Man(age:10, weight:20.5) 

kim.display() 

print("나이가 만으로 \(kim.manAge)") 
print("나이 \(kim.age)") 

kim.manAge = 3 

print("만 나이를 3살로 바꾸면 나이는 \(kim.age)")

 

class Man{

    var age : Int = 1

    var weight : Double = 3.5

    init(age: Int, weight : Double){ 

        self.age = age 

        self.weight = weight 

    } 

}

class Student: Man{

    var name : String = "김소프" 

    func displayS() 

    { 

        print("이름=\(name), 나이=\(age), 몸무게=\(weight)") 

    }

    init(age: Int, weight : Double, name : String)

    { 

        super.init(age:age, weight:weight) 

        self.name = name 

    }

}

var lee : Student = Student(age:20, weight : 65.2, name : "홍길동")  

lee.displayS()

 

스위프트 상속

class BankAccount{
    var accountBalance: Float   //현재 잔고
    var accountNumber: Int  //계좌 번호
    
    init (number: Int, balance: Float){
        accountNumber = number
        accountBalance = balance
    }

    func displayBalance(){
        print("Number \(accountNumber)")
        print("Balance \(accountBalance)")
    }
}

class SavingsAccount: BankAccount {  //class 자식:부모
//부모인 BankAccount 클래스의 모든 메서드와 속성을 상속받음 

    var interestRate: Float = 0.1   //이자율

    init(number: Int, balance: Float, rate: Float) { 
        interestRate = rate     //자신의 property 초기화 
        super.init(number: number, balance: balance)   //부모의 init호출하여 부모의 property 초기화 
    } 

    func calculateInterest() -> Float { 
        return interestRate * accountBalance 

    }

    override func displayBalance() { 
        super.displayBalance()  //부모의 메서드 호출  
        print("Prevailing interest rate is \(interestRate)") 
    }
}

var savings1: SavingsAccount = SavingsAccount(number: 12311, balance: 600.00, rate: 0.07) 

print(savings1.calculateInterest()) 

savings1.displayBalance()

- 계좌 번호와 현재 잔고를 담기위한 BankAccount에서 저축 계좌로 사용할 클래스가 필요하다면 새로운 클래스를 만드는 것보다 하위 클래스로 새로운 클래스를 만드는 것이 좋다

- accountBalance는 부모 클래스 BankAccount에 있는 프로퍼티

ex)

func calculateInterest() -> Float {

    return interestRate * accountBalance

}

- 메서드 오버라이딩을 할 때 반드시 따라야 할 두 가지 규칙

 오버라이딩 메서드는 오버라이딩되는 부모 클래스 메서드의 인자 개수와 타입이 정확하게 일치해야 한다.

 부모 클래스 메서드가 반환하는 타입과 일치해야 한다.

ex)

override func displayBalance() {

   super.displayBalance() //부모의 메서드 호출

   print("Prevailing interest rate is \(interestRate)")

}

 

- 하위 클래스에서 상위 클래스의 오버라이드된 메서드를 호출하여 중복을 없앤다

ex)

override func displayBalance() {

  ​  super.displayBalance() //부모의 메서드 호출

    print("Prevailing interest rate is \(interestRate)")

}

 

스위프트 클래스 인스텐션

- 스위프트 클래스에 새로운 기능을 추가하는 또 다른 방법은 익스텐션(Extension)을 이용하는 것이다.

- 익스텐션은 하위 클래스를 생성하거나 참조하지 않고 기존 클래스에 메서드, 초기자, 그리고 계산된 속성과

서브스크립트 등의 기능을 추가하기 위하여 사용

- 스위프트 언어의 built-in 클래스와 iOS 프레임워크에 내장된 클래스에 기능을 추가할 때, 익스텐션을 이용하면 매우 효과적임

ex)

- 표준 Double 클래스에 두 배와 세 배의 값을 반환하는 속성을 추가

extension Double { 

    var squared: Double { 
        return self * self
    } 

    var cubed: Double { 
        return self * self * self 
    } 
}

print(3.0.squared)
print(3.0.cubed)

let myValue: Double = 3.0

print(myValue.squared)     //9.0

- myValue 상수를 선언할 때 Double형이 되도록 선언하고 익스텐션 속성을 사용했는데 이 속성은 하위 클래스를 사용하는 것이 아니라 익스텐션으로 추가된 것이므로, 우리는 Double 값에서 직접 이 속성에 접근할 수 있다.

 print(3.0.squared)

 print(3.0.cubed)

- 익스텐션은 하위 클래스를 사용하지 않고 클래스에 기능을 확장할 수 있는 빠르고 편리한 방식을 제공한다

- 단, 익스텐션을 이용해서는 클래스에 있는 기존의 기능을 오버라이드할 수 으며 익스텐션은 stored property를 포함할 수도 다.