Dev/Swift

Swift: 클래스(Class)

두넌 2023. 5. 14.

DAY 12

클래스(class)

 

클래스 vs 객체 vs 인스턴스


클래스로부터 객체를 만들고 만들어진 실제 메모리상에 할당된 객체를 instance 라고 함

 

인스턴스(Instance)

소프트웨어 애플리케이션을 개발하는 데 사용되는, 쉽게 사용할 수 있으며 재사용할 수 있는 기능을 가진 모듈

 

객체의 구성


  • 데이터 변수(data variable) or 속성(property)
  • 함수 or 메서드(method)
Theory Swift Java C++
Data Property Field Member variable
Operation Method Method Member function

 

클래스


Structures and Classes

구조체와 열거형은 Value Types, 클래스는 Reference Types

일반적인 스위프트 가이드라인에서는 구조체를 사용하는 것을 더 추천한다

 

클래스에는 있지만, 구조체에는 없는 기능

  • Inheritance
  • Type casting
  • Deinitializers

 

클래스의 기본 구조


class 새로운 클래스 이름: 부모 클래스 {
    // property
    // instance method
    // type method(class method)
}

instance method 는 객체가 호출하는 메서드를 정의

type method 는 클래스가 호출하는 메서드를 정의

 

property


조건

  • 초기값이 있거나
  • init을 이용하여 초기화
  • 옵셔널 변수(상수)로 선언

property는 stored property 와 computed property 가 있음

 

stored property

class Man {
    var age: Int
    var weight: Double
}

다음과 같이 실행하면 property의 조건을 만족하지 않기 때문에 오류가 발생한다

 

stored property에 초기값을 주는 3가지 방법

// 1. 값을 직접 지정해준다
class Man {
    var age: Int = 1
    var weight: Double = 3.5
}
// 2. 옵셔널 변수로 선언한다 (Optional 변수는 `nil`로 자동 초기화 되기 때문)
class Man {
    var age: Int?
    var weight: Double!
}
// 3. initializer로 초기화
class Man {
    var age: Int
    var weight: Double
    init() {
        age = 1
        weight = 3.5
    }
}

 

computed property


computed property(계산 프로퍼티)는 property가 설정되거나 검색되는 시점에서 계산 또는 파생된 값

클래스, 구조체, 열거형에서 사용되며 stored property와 달리 저장 공간을 갖지 않고 다른 stored property의 값을 읽어 연산을 실행하거나, property로 전달받은 값을 다른 property에 저장한다

때문에 항상 var로 선언되어야 함

또한, 타입 추론을 통해 형식을 알 수 없어서, 선언할 때 자료형을 명시해야 함

  • 값을 리턴하는 게터(getter) method
  • 값을 대입하는 세터(setter) 메서드

 

getter


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

어떤 stored property의 값을 연산해서 return할 것인지, return 구문이 항상 존재해야 함

manAge는 계산 프로퍼티로 저장 프로퍼티 age의 값에서 1을 뺀 값으로 하겠다는 것을 뜻함

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

var manAge: Int {
    return age-1
}

 

setter


parameter로 받은 값을 어떤 stored property에 어떻게 설정할 것인지 구현

setter가 있으면 get{ } 는 생략할 수 없다

매개변수명은 newValue가 기본이며, parameter를 받을 때 type을 명시해주지 않는 이유는 이미 computed property를 선언할 때 타입을 반드시 명시해줬기 때문이다

set(newValue) {
    age = newValue + 1
}

 

Shorthand Setter Declaration

setter의 매개변수명이 newValue인 경우에만 이렇게 (newValue) 생략 가능

set {
    age = newValue + 1
}

 

getter와 setter를 갖는 computed property manAge

var manAge: Int {
    get { return age-1 }
    set { age = newValue + 1}
}

 

Method


instance method 와 type method 가 있다

 

instance method


인스턴스 메서드 는 인스턴스에서 동작

func ~~() 처럼, func keyword 앞에 아무것도 없는 경우 instance method

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

 

instance 생성하기

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

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

()default initializer(기본 생성자) 를 나타낸다

다음과 같이 사용할 수 있다

var kim: Man = Man()
kim.display() 
// instance.instance method

print(kim.age)
// instance.property

 

type method(class method)


type method 는 클래스 레벨에서 동작하는 것으로, 클래스의 새로운 인스턴스를 생성하는 것과 같은 동작

instance method 와 동일한 방법으로 선언하지만, classstatic 키워드를 앞에 붙여서 선언함

class 키워드로 만든 class method 는 자식 클래스에서 override 가능

class Man {
    var age: Int = 1
    var weight: Double = 3.5
    class func tm() {
        print("class method")
    }
    static func stm() {
        print("class method")
    }
}
Man.tm()
Man.stm()

 

인스턴스 초기화하기 : init()


클래스, 구조체, 열거형 인스턴스가 생성되는 시점에서 해야 할 초기화 작업

 

생성자


인스턴스가 만들어지면서 자동 호출된다

init() { }

 

designated initializer : 모든 property 를 다 초기화시키는 생성자

 

소멸자


인스턴스가 사라질 때 자동 호출

deinit{}

JAVA 언어에서 배운것과 동일하게 생성자를 하나라도 직접 만들면, default initializer는 사라진다

 

self


현재 클래스 내 methodproperty 를 가리킬 때 method, property 앞에 self. 을 붙임

매개변수 명property 명이 동일한 경우에는 구분해주기 위하여 반드시 써야함

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

 

method overloading : 생성자 중첩


매개변수의 개수와 자료형이 다른 같은 이름의 함수를 여러개 정의한 것

매개변수가 다른 두 생성자를 통해 두가지 방법으로 인스턴스를 만들 수 있다

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

 

failable initializer (실패 가능한 생성자: init?)


init?(named: String)

init?로 만든 인스턴스는 옵셔널형으로 만들어져서, 사용하려면 옵셔널을 언래핑해야 함

오류 상황에 nil을 리턴하는 조건문이 있기 때문임 return nil

class Man {
    var age: Int
    var weight: Double
    init?(age: Int, weight: Double) {
        if age <= 0 {
            return nil
        }
        else {
            self.age = age
        }
        self.weight = weight
    } // failable initialize
}
var kim: Man = Man(age:10, weight:20.5)
var lee: Man = Man(age:0, weight:3.5)

실행시키면, 다음과 같은 오류가 발생한다

error: value of optional type 'Man?' must be unwrapped to a value of type 'Man'

이는, 인스턴스를 생성할 때 실행되는 생성자가 Optional형이기 때문에 unwrapping을 하지 않아 생기는 오류이다

이는 다음과 같은 몇가지 방법으로 해결할 수 있다

// 1. 옵셔널 형으로 선언 후 옵셔널 바인딩
var kim: Man? = Man(age:1, weight:3.5)

if let kim1 = kim {
    kim1.display()
}
// 2. 인스턴스 생성과 동시에 옵셔널 바인딩
if let kim2 = Man(age:2, weight:5.5) {
    kim2.display()
}
// 3. 인스턴스 생성과 동시에 바로 강제 언래핑
var kim3: Man = Man(age:3, weight:7.5)!
kim3.display()
// 4. 옵셔널 인스턴스를 사용시 강제 언래핑
var kim4: Man? = Man(age:4, weight:10.5)
kim4!.display()

3번4번 방식으로 강제 언래핑 하는 방법은 위험함

만약 age <= 0일 때, init?nil을 반환하는데, 이때 강제 언래핑을 하고 display()를 호출하면 crash가 발생함

댓글