iOS

[iOS] 스위프트5 프로퍼티 레퍼와 에러 핸들링(Swift5 PropertyWrapper and Error Handling)

구루싸 2020. 3. 26. 23:29
반응형
SMALL

오늘은 시간이 다소 늦은 관계로

여담 없이 바로 학습으로!!

이번 주제는 제목과 같이

프로퍼티 레퍼(Property Wrapper)와 에러 핸들링(Error Handling)입니다

프로퍼티 레퍼는 스위프트 5.1부터 나온 것으로

클래스와 구조체 구현부에 getter, setter, computed property

코드의 중복을 줄이는 방법입니다

@propertyWrapper
struct FixCase {
    private(set) var value: String = ""
    
    var wrappedValue: String {
        get { value }
        set { value = newValue.uppercased() }
    }
    
    init(wrappedValue initialValue: String) {
        self.wrappedValue = initialValue
    }
}

struct Contact {
    @FixCase var name: String
    @FixCase var city: String
    @FixCase var country: String
}

var contact = Contact(name: "John Smith", city: "London", country: "United Kingdom")
print("\(contact.name), \(contact.city), \(contact.country)")

위의 코드처럼 프로퍼티 레퍼는

@propertyWrapper 지시자를 이용하여 선언되고

클래스나 구조체 안에 구현됩니다

자 위의 코드의 결과는 어떻게 될까요?

@FixCase 지시자를 붙인 프로퍼티 변수 

name, city, country는

newValue.uppercased()에 의해

모두 대문자로 변환되어 저장됩니다

어떤 클래스나 구조체의 프로퍼티들의 

공통적인 특성을 반영할 때 유용하겠네요~

@propertyWrapper
struct MinMaxVal<V: Comparable> {
    var value: V
    let max: V
    let min: V
    
    init(wrappedValue: V, min: V, max: V) {
        value = wrappedValue
        self.min = min
        self.max = max
    }
    
    var wrappedValue: V {
        get { return value }
        set {
            if newValue > max {
                value = max
            } else if newValue < min {
                value = min
            } else {
                value = newValue
            }
        }
    }
}

struct IntDemo {
    @MinMaxVal(min: 100, max: 200) var value: Int = 100
}
struct StringDemo {
    @MinMaxVal(min: "Apple", max: "Orange") var value: String = ""
}
struct DateDemo {
    @MinMaxVal(min: Date(), max: Calendar.current.date(byAdding: .month, value: 1, to: Date())! ) var value: Date = Date()
}
var demo1 = IntDemo()
demo1.value = 150
print(demo1.value)
demo1.value = 250
print(demo1.value)
var demo2 = StringDemo()
demo2.value = "Banana"
print(demo2.value)
demo2.value = "Pear"
print(demo2.value)
var demo3 = DateDemo()
demo3.value = Calendar.current.date(byAdding: .day, value: 10, to: Date())!
print(demo3.value)
demo3.value = Calendar.current.date(byAdding: .month, value: 2, to: Date())!
print(demo3.value)

위의 코드에서 V는 Foundation 프레임워크에 포함된

Comparable 프로토콜을 따르는 모든 데이터 타입을 의미합니다

이 덕분에 Int, String, Date 타입 모두를 비교할 수 있습니다

코드를 한 번 실행시켜보면 이해가 되실겁니다~

다음으로 스위프트의 에러 핸들링을 학습하겠습니다

let connectionOK = true
let connectionSpeed = 30.00
let fileFound = false
enum FileTransferError: Error {
    case noConnection
    case lowBandwidth
    case fileNotFound
}
func fileTransfer() throws {
    guard connectionOK else {
        throw FileTransferError.noConnection
    }
    
    guard connectionSpeed > 30 else {
        throw FileTransferError.lowBandwidth
    }
    
    guard fileFound else {
        throw FileTransferError.fileNotFound
    }
}
func sendFile() -> String {
    
    defer {
        removeTmpFile()
        closeConnection()
    }
    
    do {
        try fileTransfer()
    } catch FileTransferError.noConnection {
        return "No Network Connection"
    } catch FileTransferError.lowBandwidth {
        return "File Transfer Speed too low"
    } catch FileTransferError.fileNotFound {
        return "File is not found"
    } catch {
        return "Unknown error"
    }
    
    return "Successful transfer"
}

func removeTmpFile() {
    //remove temp file
}

func closeConnection() {
    //close connection
}

위의 코드를 살펴보면

먼저 enum FileTransferError: Error로 에러 타입을 선업합니다

또 함수 fileTransfer()는 에러(예외)를 던지는 함수입니다

키워드 'guard' 는 조건이 참인지 거짓인지를 검사하여

거짓이면 else 구문에 코드를 실행합니다

자 이제 실제로 이 함수를 호출하는 함수 sendFile()을 보면

먼저 defer {} 가 보입니다

defer는 메서드가 결과를 반환하기 직전에 실행되어야 하는

일련의 코드를 지정할 수 있도록 합니다

또 에러를 던지는 함수 fileTransfer()를 호출할 때 

try를 이용하여야하고

try!를 이용할 경우는

절대 에러가 나지 않을꺼라는 의미이므로 권장하지 않습니다~

이번 학습은 이 정도로 마무리하겠습니다

그럼 이만-_-

반응형
LIST