아요 개발 일기
[Swift] Class - 클래스 본문
Class
- 프로퍼티(클래스 안의 변수)와 메소드(클래스 안의 함수)를 가질 수 있는 컨테이너 타입을 정의하기위한 용도
- 일반적으로 단일 상속이 가능하지만, 프로토콜을 사용하면 다중 상속도 가능
- 참조타입 (=reference type) (call by reference)
- 형 변환(Type Casting)과 관련된 기능과 파괴자(Deinitializer)등의 기능을 가질 수 있다.
- iOS 프레임 워크의 대부분의 큰 뼈대는 모두 클래스로 구성
- 메모리의 Heap 영역에 존재
속성 (property) : 클래스에서 제공되는 변수
메소드 (method) : 클래스에서 제공되는 함수
참조 타입이 뭐에요?
참조 타입이란, 데이터의 크기가 크고 가변적이여서 동적으로 관리 되는 메모리의 힙에 생성되는 것을 말 합니다.
- 선언 : 선언에 의해 참조만 생성될 뿐이지 데이터를 저장할 수 있는 실제 메모리가 할당되는 것은 아니므로 선언 즉시 사용할 수 없으며, 반드시 new 연산자로 메모리를 할당 받아 초기화 해야 합니다.
- 종료 : 더 이상 참조하는 변수가 없을 때 가비지 컬렉터에 의해 파괴 됩니다.
- 데이터 : 참조 타입끼리의 대입은 힙에 할당된 데이터를 참조하는 참조자가 하나 더 늘어날 뿐 별도의 메모리가 추가로 할당되는 것은 아닙니다. 그래서 둘 중 하나를 변경하면 상대 쪽도 같이 변경 됩니다.
Heap에 대해 자세히 알고 싶은 분들은 메모리 구조 (feat.Stack과 Heap)포스팅을 참고해주세요!
클래스에 대해 이론적으로 보았으니, 정의와 구현을 해볼까요?
정의 및 구현
아래는 정의 방식입니다.
class 클래스명 {
... }
이제 구현해 볼까요? Exm이라는 클래스를 만들어 보았습니다!
class Exm {
var name = "Sojin";
func say(){
print("Hello, " + name + "!");
}
}
위 클래스에는 name이라는 속성과 say라는 메소드가 있습니다. name 과 say 모두 기능이겠죠?
say 메소드 안에 name 속성이 사용되고 있는 것 처럼 클래스에 있는 메소드에 내부는 그 클래스에 있는 속성과 메소드를 그대로 사용할 수 있도록 되어있습니다.
클래스 밖에서 사용하기 위해서 인스턴스를 생성해 볼까요?
인스턴스에 대해서 모르겠는 분은 OOP와 POP 포스팅을 참고해주세요!
실행해보기
인스턴스를 생성했으니, 한번 활용해서 실행해봅시다!
class Exm {
var name = "Sojin"
func say(){
print("Hello, " + name + "!")
}
}
var obj:Exm = Exm(); // 인스턴스 생성
obj.say(); // Hello, Sojin!
obj.name = "Hanako"; // Sojin -> Hanako
obj.say(); // Hello, Hanako
코드를 보니, 클래스 내부에 생성되어있는 객체(변수) 값을 변경 할 수도있네요?
이제 클래스의 큰 특징인 상속을 해보겠습니다!
상속하기
먼저 코드를 보기 전에 상속 코드는 어떻게 작성하는 걸까요?
class 자식 클래스명 : 부모 클래스명 {
...
}
오른쪽에 : 부모클래스명만 추가 되었죠?! 어렵지 않아요!
위와 같은 부모 클래스를 상속 받아 새로운 자식 클래스를 만드는 과정을 서브 클래싱(Subclassing)이라고 합니다:-)
이제 코드 예시로 이해해볼까요?
Hello 클래스가 Helo 클래스를 상속 받고있는 코드 입니다.
class Helo {
var name:String = "Sojin";
func say(){
print("Hello, " + name + "!");
}
}
class Hello:Helo {
var name2:String = "YAMADA";
func say2(){
print("Hi," + name + "-" + name2 + "!");
}
}
var obj:Hello = Hello();
obj.say();
obj.name = "Sojin";
obj.name2 = "TANAKA";
obj.say2();
위 코드에서는 Hello 클래스 인스턴스만 생성했는데 Helo클래스의 함수와 객체를 선언해서 문제 없이 사용하고 있는 것을 볼 수 있습니다.
이유는 당연히 상속을 사용했기 때문이겠지요? Hello 클래스(자식 클래스) 가 Helo 클래스(부모 클래스)를 상속 받았기 때문에 부모 클래스인 Helo의 객체와 함수등을 모두 가져다가 사용할 수 있는 것입니다!
initializer (생성자) & Deinitializer
생성자는 인스턴스가 생성될 때의 형식과 할 일을 정의하는 부분입니다!!
생성자에 관련된 자세한 내용은 생성자(initializer) 포스팅을 참고해주세요!
struct Grade {
var letter: Character
var points: Double
var credits: Double
}
class Person {
var firstName: String
var lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
func printMyName() {
print("My name is \(firstName) \(lastName)")
}
}
class Student: Person {
var grades: [Grade] = []
override init(firstName: String, lastName: String) {
super.init(firstName: firstName, lastName: lastName)
}
convenience init(student: Student) {
self.init(firstName: student.firstName, lastName: student.lastName)
}
}
// 학생인데 운동선수
class StudentAthlete: Student {
var minimumTrainingTime: Int = 2
var trainedTime: Int = 0
var sports: [String]
init(firstName: String, lastName: String, sports: [String]) {
// Phase 1
self.sports = sports
super.init(firstName: firstName, lastName: lastName)
// Phase 2
self.train()
}
convenience init(name: String) {
self.init(firstName: name, lastName: "", sports: [])
}
func train() {
trainedTime += 1
}
}
// 운동선인데 축구선수
class FootballPlayer: StudentAthlete {
var footballTeam = "FC Swift"
override func train() {
trainedTime += 2
}
}
let student1 = Student(firstName: "Jason", lastName: "Lee")
let student1_1 = Student(student: student1)
let student2 = StudentAthlete(firstName: "Jay", lastName: "Lee", sports: ["Football"])
let student3 = StudentAthlete(name: "Mike")
deinit
- 클래스 타입에서만 구현 가능
- deinit은 클래스의 인스턴스가 메모리에서 해제되는 시점에서 호출
- 인스턴스 해제되는 시점에 해야할 일을 구현
class PersonE {
var name: String
var pet: Puppy?
var child: PersonC
init(name: String, child: PersonC) {
self.name = name
self.child = child
}
deinit { //사람이 사망했을 때 다른 주인에게 인도 (인스턴스가 해제되는 시점에 해야할 일)
if let petName = pet?.name {
print("\(name)가 \(child.name)에게 \(petName)를 인도합니다.")
self.pet?.owner = child
}
}
}
var donald: PersonE? = PersonE(name: "donald", child: jenny)
donald?.pet = happy
donald = nil // donald 인스턴스가 더이상 필요없으므로 메모리에서 해제됩니다.
//donald가 jenny에게 happy를 인도합니다
클래스만 가능한 기능
- 상속 : 클래스의 특성을 다른 클래스에게 물려줄 수 있다.
- 타입 캐스팅 : 실행 시 컴파일러가 클래스 인스턴스의 타입을 미리 파악하고 검사할 수 있다.
- 소명화 구문 : 인스턴스가 소멸되기 직전에 처리해야 할 구문을 미리 등록해 놓을 수 있다.
- 참조에 의한 전달 : 클래스 인스턴스가 전달될 때에는 참조 형식으로 제공되며, 이때 참조가 가능한 개수는 제약이 없다.
채택과 상속?
- 클래스 상속 : 상속받을 클래스의 모든 기능을 물려 받는 기능
- Single Responsibility(단일 책임)
- Type Safety (타입이 분명해야할떄)
- Shared Base Classes (다자녀가 있을때)
- Extensibility(확장성이 필요한 경우)
- Identity(정체를 파악하기 위해)
- 프로토콜 채택 : 내가 이제 이 프로토콜을 준수하겠어! 라는 뜻
Class를 써야하는 경우
1. 두 object의 인스턴스 자체가 같음을 확인해야할 떄
2. 하나의 객체가 필요하고, 여러 대상에 의해 접근되고 변경이 필요한 경우
'Swift > Grammar' 카테고리의 다른 글
[Swift] 조건문 - Switch case (0) | 2023.01.29 |
---|---|
[Swift] Struct - 구조체 (0) | 2023.01.27 |
[Swift] 고차 함수 (0) | 2023.01.27 |
[Swift] 오류처리 (0) | 2023.01.27 |
[Swift] Extension - 익스텐션 (0) | 2023.01.27 |