About swift – 클래스(3), “failable initializer , 상속”
About swift – 클래스(3), “failable initializer , 상속”
failable initializer
실패 가능한 생성자라는 뜻인데, init 다음에 느낌표 혹은 물음표를 쓰며 옵셔널 값이 리턴됩니다.
class Man{
var age : Int
var weight : Double
func display(){
print("나이=\(age), 몸무게=\(weight)")
}
init?(age: Int, weight : Double){
if age <= 0 {
return nil
}
else {
self.age = age
}
self.weight = weight
}
}
var kim : Man = Man(age:10, weight:20.5)!
kim.display()
var lee : Man = Man(age:0, weight:3.5)!
lee.display()
여기에서, init? 부분을 살펴볼 수 있습니다. age에 음수나 0이 대입되면 nil을 리턴하는 것입니다. 옵셔널 변수나 상수를 가지고 놀았을 때처럼, 우리는 그것을 다루기 위해서는 언래핑을 해주어야 합니다. 18줄과 20줄에서처럼 강제 언래핑을 하는 방법도 있습니다.
이제부터, 실패 가능한 생성자를 사용했을 시에 어떻게 인스턴스를 생성하는지에 대한 몇 가지 방법을 알아보도록 하겠습니다.
class Man{
var age : Int
var grade : Int
var weight : Double
func display()
{
print("나이 = \(age)")
print("학년 = \(grade)")
print("체중 = \(weight)")
}
init?(age : Int, grade : Int, weight : Double)
{
if age <= 0 {
return nil
}
else {
self.age = age
}
self.grade = grade
self.weight = weight
}
}
이것은 failable initialize가 있는 클래스입니다. 프로퍼티로 age, grade, weight을 가지며 메소드는 display를 가집니다. init 메소드를 보시면, age가 음수나 0이 대입될 경우에는 nil을 반환한다고 써져 있네요. 당연히, nil을 반환할 수도 있고 아닐 수도 있는 것은 optional로 선언되어야 하고 init은 “?”을 사용해 선언되었습니다.
var kim : Man? = Man(age:1, grade:3, weight:55)
if let kim1 = kim {
kim1.display()
}
첫 번째 방법은 옵셔널 형으로 선언하는 것입니다. Man?형으로 인스턴스를 생성한 뒤, 옵셔널 바인딩 형식으로 그것을 풀어주는 것입니다.
if let kim2 = Man(age:28,grade:3, weight:5.5) {
kim2.display()
}
두 번째 방식은 인스턴스를 생성함과 동시에 옵셔널 바인딩을 진행해 주는 것입니다. 첫 번째 방식을 요약해서 써 놓은 것으로 이해하면 좋을 것 같습니다.
var kim3 : Man = Man(age:3, grade:1, weight:7.5)!
kim3.display()
세 번째 방법은 인스턴스를 생성하고 바로 강제 언래핑해주는 방법입니다.
위의 경우에서는 애초에 nil값이 리턴될 상황이 없었지만(age<=0), 아래의 경우를 살펴봅시다.
if let kim2 = Man(age:0 ,grade:3, weight:5.5) {
kim2.display()
}
var kim3 : Man = Man(age:-23, grade:1, weight:7.5)!
kim3.display()
위의 방식(선언과 동시에 옵녀설 바인딩)으로는 오류가 나지 않지만, kim3의 방식처럼 바로 강제 언래핑을 해버리면 크래쉬가 날 것입니다. 웬만하면 옵셔널 바인딩 형식을 사용하는 것이 크래쉬가 나지 않는 프로그램을 작성하는 데에 도움이 될 것 같습니다.
상속
상속은 기본적으로 부모가 가진 것을 물려받는다는 의미를 가집니다. Swift에서 그것은 클래스만 가능합니다.
class 상속받을클래스이름 : 부모클래스이름
의 코드로 상속할 수 있습니다. 콜론 다음에 여러 단어가 오면 나머지는 프로토콜을 가리키는 것인데, 이는 다음 포스팅에 써놓겠습니다.
class Man{
var age : Int = 1
var weight : Double = 3.5
func display(){
print("나이=\(age), 몸무게=\(weight)")
}
init(age: Int, weight : Double){
self.age = age
self.weight = weight
}
}
class Student : Man {} // 상속!
var lee : Student = Student(age:20,weight:65.2)
lee.display()
print(lee.age)
이는 간단한 Man 클래스와 그것을 상속한 Student 클래스를 만들어 본 예제입니다. 분명 15줄에 보시면, Student 클래스의 내용은 비어 있습니다. 하지만, 상속의 개념으로 Man클래스의 모든 것을 물려받았기 때문에, 17줄과 18줄에서처럼 호출하고 사용할 수 있는 것입니다.
class Man{
var age : Int
var weight : Double
func display(){
print("나이=\(age), 몸무게=\(weight)")
}
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){
self.name = name
super.init(age:age, weight:weight)
}
}
var lee : Student = Student(age:20,weight:65.2,name:"김애플")
lee.displayS()
lee.display()
위의 코드에서는 상속할 때 super라는 키워드가 어떻게 쓰이는지를 알려줍니다. 분명히 Student라는 클래스에는 age라는 프로퍼티가 없는 것을 볼 수 있습니다. 하지만, super.init이라는 문장을 통해 부모 클래스의 생성자를 호출하였고, 그것이 이 코드를 문제없이 동작하도록 해 준 것입니다. super이라는 키워드를 통하여 부모 클래스를 호출할 수있습니다.
class Man{
var age : Int = 1
var weight : Double = 3.5
func display(){
print("나이=\(age), 몸무게=\(weight)")
}
init(age: Int, weight : Double){
self.age = age
self.weight = weight
}
}
class Student : Man {
var name : String = "김애플"
override func display() {
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.display()
위의 코드는 overriding의 예시인데, 부모 클래스와 자식 클래스 모두 func display()로 메소드가 선언되어져 있는 것을 알 수 있습니다. 하지만, 상속된 경우 자식 클래스를 우선으로 하여 호출됩니다. 자식 클래스의 메소드 선언 부분의 override 때문입니다.