100 days of swiftui: 12
https://www.hackingwithswift.com/100/swiftui/12
class는 strut처럼 특정 속성을 모은 구조라고 할 수 있다. 그 속성에 대해 접근 지정자, property observer, initializer를 설정할 수 있다.
그러나 struct와 달리 class는 다음 다섯 가지 특징을 지닌다.
1. You can make one class build upon functionality in another class, gaining all its properties and methods as a starting point. If you want to selectively override some methods, you can do that too. (다른 class를 상속할 수 있다.)
2. Because of that first point, Swift won’t automatically generate a memberwise initializer for classes. This means you either need to write your own initializer, or assign default values to all your properties. (swift가 memberwise initializer를 제공하지 않는다.)
3. When you copy an instance of a class, both copies share the same data – if you change one copy, the other one also changes. (instance를 복사하면 데이터를 복사하는 것이 아닌 참조한다.)
4. When the final copy of a class instance is destroyed, Swift can optionally run a special function called a deinitializer. (데이터를 참조하는 인스턴스가 없어지면 deinitializer를 실행한다.)
5. Even if you make a class constant, you can still change its properties as long as they are variables. (class를 상수로 만들어도 속성이 변수면 변경할 수 있다.)
class는 이미 존재하는 다른 class를 상속할 수 있다. 상속하면 그 class의 속성을 모두 가진다.
예시로 hours
라는 멤버 변수를 가지는 Person
이 있고, 이를 상속하는 Baby
와 Teenager
를 만들었다.
class Person {
var hours: Int
init(hours: Int) {
self.hours = hours
}
}
class Baby: Person {
func sleep() {
print("I sleep for \(hours) hours. Wah!")
}
}
class Teenager: Person {
func sleep() {
print("I sleep for \(hours) hours. Yay!")
}
}
var baby1 = Baby(hours: 12)
baby1.sleep()
var teenager1 = Teenager(hours: 8)
teenager1.sleep()
결과:
I sleep for 12 hours. Wah!
I sleep for 8 hours. Yay!
이렇게 Person
의 멤버 변수를 Baby
와 Teenager
에서 활용할 수 있다.
추가로 모든 사람은 자니까 Person
에서 sleep()
메소드를 설정할 수도 있다.
class Person {
var hours: Int
init(hours: Int) {
self.hours = hours
}
func sleep() {
print("I sleep for \(hours) hours.")
}
}
class Baby: Person {
}
class Teenager: Person {
override
func sleep() {
print("I sleep for \(hours) hours. Yay!")
}
}
var baby1 = Baby(hours: 12)
baby1.sleep()
var teenager1 = Teenager(hours: 8)
teenager1.sleep()
이 경우엔 상속받는 subclass에서 Person
의 sleep()
과 달리하고 싶다면 override 키워드를 작성해야 한다.
결과:
I sleep for 12 hours.
I sleep for 8 hours. Yay!
❗️ 더이상 상속하지 않을 때는 final 키워드를 작성한다.
코드 파일
https://github.com/soaringwave/Ios-studying/commit/18e868797e23868b36b1ae2c4f4f1b8a7881f49a
swift는 class에 memberwise initializer를 제공하지 않는다. 그렇기 때문에 적절한 initializer를 설정해야 한다. subclass에서는 superclass의 멤버 변수나 상수 값을 받아 전달해야 한다.
예: Furniture
를 상속받는 Chair
를 상속받는 Armchair
를 정의하는 방법
class Furniture {
var isNeeded: Bool
init(isNeeded: Bool) {
self.isNeeded = isNeeded
}
}
class Chair: Furniture {
var isComfortable: Bool
init(isNeeded: Bool, isComfortable: Bool) {
self.isComfortable = isComfortable
super.init(isNeeded: isNeeded)
}
}
class Armchair: Chair {
var isAwesome = true
}
var newArmChair = Armchair(isNeeded: true, isComfortable: false)
코드 파일
https://github.com/soaringwave/Ios-studying/commit/1eb9eb70171a68b5c7f86b676b05e4c7b10b4f84
class의 instance를 복사하면 속성의 값은 참조된다. 그래서 아래와 같은 결과를 얻을 수 있다.
class Cat {
var age = 0
}
var cat1 = Cat()
var cat2 = cat1
cat2.age = 3
print(cat1.age)
print(cat2.age)
결과:
3
3
만약 속성의 값을 참조하지 않고 복사(deep copy)만 하고 싶다면 다음을 활용할 수도 있다.
class Cat {
var age = 0
func copy() -> Cat {
var newCat = Cat()
newCat.age = self.age
return newCat
}
}
var cat1 = Cat()
var cat2 = cat1.copy()
cat2.age = 3
print(cat1.age)
print(cat2.age)
결과:
0
3
코드 파일
https://github.com/soaringwave/Ios-studying/commit/379df35480ef3b5dd995fbfe923996c7c0529d27
class를 만들 때는 init을 사용하듯이 더 이상 참조할 게 없으면(class를 사용하지 않으면) deinit한다. 이것을 deinitializer가 실행한다.
()
와 화살표->
를 사용하지 않는다.)예:
class User {
let id: Int
init(id: Int) {
self.id = id
print("User \(id): I'm alive!")
}
deinit {
print("User \(id): I'm dead!")
}
}
for i in 1...3 {
let user = User(id: i)
print("User \(user.id): I'm in control!")
}
결과:
User 1: I'm alive!
User 1: I'm in control!
User 1: I'm dead!
User 2: I'm alive!
User 2: I'm in control!
User 2: I'm dead!
User 3: I'm alive!
User 3: I'm in control!
User 3: I'm dead!
이렇게 반복문을 돌면서 생성된 user는 반복문이 끝나는 대로 사라지기 때문에 deinitializer가 자동으로 실행되는 모습을 확인할 수 있다.
코드 파일
https://github.com/soaringwave/Ios-studying/commit/f7058d8719ac3fedbab9a045b954e5c307667a33
class의 instance가 상수여도 변수여도 멤버 변수를 변경할 수 있다.
class Human {
var name = "Paul"
}
// 1
let human1 = Human()
human1.name = "Taylor"
print(human1.name)
// 2
var human2 = Human()
human2.name = "Taylor"
human2 = Human()
print(human2.name)
결과:
Taylor
Paul
1의 경우는 human1
은 상수지만 name
은 변경된다. 그리고 2의 경우는 human2
를 나중에 새로운 Human
으로 설정했다. class와 속성의 이름으로 이 경우들을 설명하자면, 1은 사람은 그대로이나 이름을 변경한 경우이고(상수이기 때문에 사람을 변경할 수는 없다) 2는 사람은 그대로이나 이름을 변경했다가 새로운 사람로 변경한 경우다(변수이기 때문에 사람을 변경할 수 있다).
class의 instance와 속성이 변수인지 상수인지에 따라 네 가지의 경우로 나뉘고, 이로 인해 할 수 있는 점도 달라진다. 이는 상수 instance는 속성이 변수인지 상수인지와는 상관없이 수정되지 않는 struct와는 다르다. 그렇기에 class는 mutating 키워드를 사용하지 않는다.
코드 파일
https://github.com/soaringwave/Ios-studying/commit/6689eb17d2a2f80aa627a29b6b706799e6afac1b