Swift의 클래스 역시 구조체처럼 관계가 있는 것들을 묶어서 표현할 때 사용됩니다. 구조체와 마찬가지로 기본적인 구조는 프로퍼티와 메서드로 구성되어있습니다. 구조체를 클래스로 변경이 쉬울 만큼 구현 문법이 동일합니다. 클래스를 알아보고 구조체와 클래스의 차이점에 대해서 알아보겠습니다.
Class(클래스) 정의하기
class 클래스 이름 {
// 프로퍼티
// 메서드
}
클래스의 간단한 형태입니다 class
로 지칭할 수 있으며 property
와 method
를 가질 수 있습니다.
class Person {
var firstName: String = ""
var lastName: String = ""
// 따로 initializers를 정의하지 않고 프로퍼티를 초기화 해주어도 됩니다.
func printMyName() {
print("My name is \(firstName) \(lastName)")
}
}
Person
를 만들어 보겠습니다. firstname
과 lastName
프로퍼티를 가지고 있습니다. 저장형 프로퍼티가 초기화가 되어있지 않으면 에러가 발생하게 됩니다.
Class 'Person' has no initializers 초기화를 해야 된다고 알려 주고 있습니다.
해당 Person 클래스의 경우 Stored Property 값이 초기화되어있기 때문에 initializers
생성자를 직접 만들어 주지 않아도 에러가 발생하지 않습니다.
Initializer, Deinitializers
class Person {
var firstName: String
var lastName: String
//initializers
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
//Deinitializers
deinit {
print("인스턴스 소멸")
}
func printMyName() {
print("My name is \(firstName) \(lastName)")
}
}
let minmong: Person? = Person(firstName: "minmong", lastName: "Ji")
minmong.printMyName()
// 결과 : My name is minmong Ji
minmong = nil
// 결과 : 인스턴스 소멸
클래스에는 생성자와, 소멸자의 개념처럼 initializers
와 Deinitializers
가 있고 생성자, 소멸자로 알아 두면 됩니다. 클래스가 객체화 인스턴스 될 때에 생성자가 실행됩니다. init
이라는 메서드를 이용해서 생성자를 만들어 줄 수 있습니다.
생성자를 추가하게 되면 인스턴스시 파라미터 값이 필요하게 됩니다. deinit
은 클래스 인스턴스가 사라 질 때에 즉 메모리에서 해제되기 직전에 호출됩니다. 또한 매개변수, 반환 값을 가질 수 없습니다. C++에서는 소멸자에서 보통 메모리 해제가 되도록 코드 추가를 하지만 스위프트는 ARC(Auto Reference Counting)을 하기 때문에 필요가 없다고 하네요.
Class 상속
상속은 클래스와 구조체의 차이점 중 하나입니다. 상속이란 부모 클래스(Super Class)의 속성과 기능을 자식 클래스(Sub Class)에서 이어받을 수 있게 됩니다. 상속을 할 때에는 A is B
라는 개념을 생각해 보면 됩니다.
예를 들면 학생은 사람이다. 라는 명제 가있습니다. Student is Person 학생은 사람에 포함이 됩니다. 반대로 사람은 학생이다. 참이 될 경우 모든 사람이 학생은 아니기 때문에 성립할 수가 없게 되며 이렇게 설계가 되었을 경우 나중에 문제가 발생할 수 있습니다.
여기서 우리는 이미 Person
이라는 클래스를 가지고 있고 Student
라는 클래스를 만들때에Person
클래스를 상속할 수 있습니다.
// Person 상속하기
class Student: Person {
var grades: [Grade] = []
init(firstName: String, lastName: String, grades: [Grade]) {
self.grades = grades
//부모 클래스를 부를 때 super를 사용하면 된다.
//부모 생성자
super.init(firstName: firstName, lastName: lastName)
}
}
var math = Grade(letter: "B", points: 8.5, credits: 3)
var myGrades = Array<Grade>()
myGrades.append(math)
let minmong = Student(firstName: "minmong", lastName: "Ji", grades: myGrades)
Person
클래스를 상속 받고 있는 Student
클래스 입니다. 상속을 할 때에는 : 클래스 이름
을 통해서 할 수 있습니다. 상속을 하게 되면 Person
클래스의 프로퍼티와 메서드를 사용할 수 있습니다. 상속받은 Student
클래스 생성자에서 부모의 생성자를 호출해주지 않으면 에러가 발생하게 됩니다.
이번에는 학생인minmong
이를 인스턴스 했습니다. 학생에는 성적이라는 프로퍼티가 추가되었습니다. 이렇게 미리 만들어진 Person의 프로퍼티와 메서드는 상속을 받게 되면 자식 클래스에서 추가 적인 코드 작업 없이 사용할 수 있게 됩니다.
상속의 규칙
- 자식은 한개의 superclass를 가질 수 있습니다.
- superclass는 여러 자식을 가질 수 있습니다.
- 상속의 깊이는 제한이 없습니다.
상속에는 규칙이 있습니다. Swift에서는 하나의 부모 클래스(superclass)를 가질 수 있기 때문에 다중 상속을 받을 수 없습니다. 또한 예시에서 Person 클래스는 또 다른 직업의 부모 클래스가 될 수 있듯이 자식을 둘 수 있는 제한이 없습니다.
class StudentAthlete: Student {
var minimumTrainingTime: Int = 2
var trainedTime: Int = 0
var sports: String = ""
}
상속의 깊이의 제한이 없다는 말은 상속받은 Student
클래스가 다른 클래스의 부모가 될 수 있다는 뜻입니다.
designated initialization, convenience initialization
class Student: Person {
var grades: [Grade] = []
init(firstName: String, lastName: String, grades: [Grade]) {
self.grades = grades;
super.init(firstName: firstName, lastName: lastName)
}
convenience init(grades: [Grade]) {
self.init(firstName: "minmong", lastName: "ji", grades: grades)
}
}
앞에서 사용한 이니셜라이저(생성자)는 Designated initialization
라고 하는데요. Swift에서는 Convenience initialization
도 있습니다. 편의 초기화라고 하는데요. 보조 이니셜라이저입니다. 파라미터가 너무 많아질 경우 Designated init의 값들을 기본값으로 설정하고 보조 이니셜라이저를 통해서 인스턴스를 할 수 있습니다.
규칙
Designated initialization
는 자신의 부모의Designated initialization
를 호출해야한다.Convenience initialization
는 같은 클래스의initializers
를 꼭 하나 호출해야 한다.Convenience initialization
는 궁극적으로는Designated initialization
를 호출해야 한다.
추천글 입니다.