iOS

웹개발자의 iOS 개발기(5) - 예외 처리, 프로토콜, 제네릭

whh__ 2025. 1. 24. 22:57

예외 처리, 프로토콜, 제네릭에 대하여 공부해 보았습니다.

01. 예외처리 - 만약 에러가 발생한다면?

import SwiftUI

struct _1_Exception: View {
    
    @State var inputNumber = ""
    @State var resultNumber: Float = 0
    
    var body: some View {
        VStack {
            TextField("나눌 숫자를 입력해주세요", text: $inputNumber)
            Text("나눈 결과는 다음과 같아요 \\(resultNumber)")
            Button {
                
                do {
                    try resultNumber = devideTen(with: (Float(inputNumber) ?? 1.0))
                } catch DivideError.dividedByZero {
                    print("0으로 나누었대요")
                    resultNumber = 0
                } catch {
                    print(error.localizedDescription)
                }
                
            } label: {
                Text("나누기")
            }
        }
    }
    
    func devideTen(with inputNumber: Float) throws -> Float {
        var result: Float = 0
        
        if inputNumber == 0 {
            throw DivideError.dividedByZero
        } else {
            result = 10 / inputNumber
        }
        
        return result
    }
}

enum DivideError: Error {
    case dividedByZero
}

#Preview {
    _1_Exception()
}

02. 프로토콜 - 설계하고 설계대로 만드는 방법

import SwiftUI

struct _2_Protocol: View {
    
    var myCar: KIA = KIA()
    var broCar: Hyundai = Hyundai()
    let cars: [Driveable] = [KIA(), Hyundai()]
    
    @State var speed: Int = 10
    
    var body: some View {
        VStack {
            Text("speed : \\(speed)")
            
            Button {
                //speed = myCar.speedDown(with: speed)
                speed = broCar.speedDown(with: speed)
            } label: {
                Text("감속!")
            }
        }
        
//        ForEach(cars) { item in
//            
//        }
        
    }
}

/*
 * 위의 ForEach를 수행하기 위해서 Identifiable 키워드 사용
 * 자동으로 var id: ObjectIdentifier도 생성된다.
 */
//struct KIA: Driveable, Identifiable {
struct KIA: Driveable {
    
    //var id: ObjectIdentifier
    
    func speedDown(with speed: Int) -> Int {
        print("속도가 천천히 줄어듭니다.")
        return speed - 5
    }
}

struct Hyundai: Driveable {
    func speedDown(with speed: Int) -> Int {
        print("속도가 빠르게 줄어듭니다.")
        return speed - 9
    }
}

protocol Driveable {
    func speedDown(with speed: Int) -> Int
}

#Preview {
    _2_Protocol()
}

자바의 인터페이스와 유사

03. 제네릭 - 모든 타입을 커버하는 방법

제네릭

  • 타입에 의존하지 않는 범용코드
import SwiftUI

struct _3_Generic: View {
    
    @State var input = ""
    //@State var myStack = MyStack()
    //@State var myFloatStack = MyFloatStack()
    @State var myStack = MyStack<Int>()
    
    var body: some View {
        VStack {
            TextField("숫자를 입력해주세요", text: $input)
            Button{
                myStack.insertValue(input: Int(input) ?? 0)
            } label: {
                Text("저장")
            }
            Button {
                myStack.showData()
            } label: {
                Text("출력")
            }
        }
        
    }
}

//struct MyStack {
//    var data: [Int] = []
//    
//    mutating func insertValue(input: Int) {
//        data.append(input)
//    }
//    
//    func showData() {
//        data.forEach { item in
//            print(item)
//        }
//    }
//}

/*
 Generic을 사용하지 않으면 타입별 구조체를 생성해야 한다.
 */
//struct MyFloatStack {
//    var data: [Float] = []
//    
//    mutating func insertValue(input: Float) {
//        data.append(input)
//    }
//    
//    func showData() {
//        data.forEach { item in
//            print(item)
//        }
//    }
//}

/*
 Generic을 이용한 리팩토링
 */
struct MyStack<T> {
    var data: [T] = []
    
    mutating func insertValue(input: T) {
        data.append(input)
    }
    
    func showData() {
        data.forEach { item in
            print(item)
        }
    }
}

#Preview {
    _3_Generic()
}