실패가능 생성자

쏘스야·2023년 4월 17일
0

ios 개발자의 첫걸음

목록 보기
60/61
/**
 
 실패가능 생성자
 
 - 실패가능 생성자는 인스턴스 생성에 실패할 수도 있는 가능성을 가진 생성자 (클래스, 구조체, 열거형 가능)
  ( 실패가 불가능하게 만들어서, 아예 에러가 나고 앱이 완전히 꺼지는 가능성보다는
   실패가능 가능성 생성자를 정의하고 그에 맞는 예외 처리를 하는 것이 더 올바른 방법임)
 
 - 생성자에 ?를 붙여서 init(파라미터) 라고 정의하면 실패가능 생성자로 정의되는 것임
  (다만, 동일한 파라미터를 가진 생성자는 유일해야함. 오버로딩으로 실패가능 / 불가능을 구분 짖지 못함)
 
 */


struct Animal {
    let species: String
    
    // 실패가능 생성자
    init?(species: String) {
        if species.isEmpty {
            return nil
        }
        self.species = species
    }
}


let a = Animal(species: "Giraffe")

let b = Animal(species: "")



// 엄밀히 말하면 생성자는 값을 반환하지 않고, 초기화가 끝날 때까지 모든 저장 속성이 값을 가져 올바르게 초기화되도록하는 것임
// 초기화 성공을 나타내기 위해 return 키워드를 사용하지 않음 (문법적 약속)


/**
 열거형의 실패가능 생성자 활용
 */

enum TemperatureUnit {
    case kelvin
    case celsius
    case fahrenheit
    
    // 실패가능 생성자
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .kelvin
        case "C":
            self = .celsius
        case "F":
            self = .fahrenheit
        default:
            return nil
        }
    }
}



let c: TemperatureUnit = TemperatureUnit.celsius        // 옵셔널타입이 아님

let f: TemperatureUnit? = TemperatureUnit(symbol: "F")  // 실패가능하기 때문에 옵셔널 타입임.

let x: TemperatureUnit? = TemperatureUnit(symbol: "X")


enum temperatureUnit1: Character {
    case kelvin = "K"
    case celsius = "C"
    case fahrenheit = "F"
}


let f1: temperatureUnit1? = temperatureUnit1(rawValue: "F")

let c1: temperatureUnit1? = temperatureUnit1(rawValue: "C")



// 1. 초기화 실패의 전달 (호출관계)

/**
 - (한마디로) 실패불가능 생성자는 다른 실패가능 생성자를 호출 불가능 🤙🏻
 
 (동일단계 - 델리게이트 어크로스)
 - 실패가능 ===> 실패불가능        (호출/위임)     (OK)
 - 실패불가능 ===> 실패가능        (호출/위임)     (X)
 
 (상속관계 - 델리게이트 업)
 - (상위) 실패가능 <=== (하위)실패불가능     (호출/위임)     (X)
 - (상위) 실패불가능 <=== (하위)실패가능     (호출/위임)     (OK)

 - 두 경우 모두 초기화 실패를 유발하는 다른 생성자에 위임하면
 - 전체 초기화 프로세스가 즉시 실패하고 더 이상 초기화 코드가 실행되지 않음
 
 */

// 예제 1

struct Item {
    var name = ""
    
    // 실패불가능 생성자
//    init() {
//
//    }
    
    init() {
//        self.init(name: "헬로")     // 실패불가능은 실패가능을 호출할 수 없다.
    }
    
    
    // 실패가능 생성자
    init?(name: String) {
        self.init()     // 실패가능은 실패불가능 호출을 할 수 있다.
    }
}



// 상속관계에서의 호출 예제

// 상품
class Product {
    let name: String
    
    init?(name: String) {
        if name.isEmpty {return nil}
        self.name = name
    }
}


// 온라인 쇼핑 카트의 항목을 모델링

class CartItem: Product {
    let quantity: Int
    init?(name: String, quantity: Int) {
        if quantity < 1 {return nil}
        self.quantity = quantity
        super.init(name: name)
    }
}

if let twoSocks = CartItem(name: "sock", quantity: 2) {
    print("아이탬: \(twoSocks.name), 수량: \(twoSocks.quantity)")
}

if let zeroShirts = CartItem(name: "shirt", quantity: 0 ) {
    print("아이템: \(zeroShirts.name), 수량: \(zeroShirts.quantity)")
} else {
    print("zero shirts를 초기화 불가(갯수가 없음)")
}

if let oneUnnamed = CartItem(name: "", quantity: 1) {
    print("아이템: \(oneUnnamed.name), 수량: \(oneUnnamed.quantity)")
} else {
    print("이름없는 상품 초기화 불가")
}


// 2) (상속관계에서) 재정의 하기


/**
 - (상위) 실패가능 ===> (하위) 실패불가능        재정의     (OK)    (강제 언래핑 활용 가능)
 - (상위) 실패불가능 ===> (하위) 실패가능        재정의     (X)
 */

// 범위로 따져보기(실패가능 생성자의 범위가 더 큼)

// 서류라는 클래스 정의
class Document {
    var name: String?
    
    init() {}
    
    init?(name: String) {
        if name.isEmpty { return nil}
        self.name = name
    }
}


// 자동으로 이름지어지는 서류
class AutomaticallyNamedDocument: Document {
    
    override init() {                   // 재정의 (상위) 실패불가능 ====> (하위) 실패불가능
        super.init()
        self.name = "[Untitled]"
    }
    
    override init(name: String) {       // 재정의 (상위) 실패가능 ====> (하위) 실패불가능
        super.init()                    // 실패불가능 활용가능
        if name.isEmpty {
            self.name = "[Untitled]"
        } else {
            self.name = name
        }
    }
}

let autoDoc = AutomaticallyNamedDocument(name: "")
autoDoc.name



// 이름없는(Untitled) 서류

class UntitledDocument: Document {
    override init() {                   // 재정의 (상위) 실패가능 ====> (하위) 실패불가능
        super.init(name: "[Untitled]")! // 강제 언래핑(!)으로 구현 🤙🏻
    }
}


/**
 실패가능 생성자를 init!(파라미터)로 정의하기
 */


profile
개발자

0개의 댓글