Programming/Swift(iOS)

Swift 오류 처리 - 2

홍열 2021. 4. 6. 09:51
728x90

만약 데이터를 더하다가 오류가 났을때는 이미 추가된 데이터는 어떻게 해야될까요?

 

1, 이전 데이터로 돌린다. 

2. 오류 이전까지만 추가한다.

 

개발자 혹은 기획이 어떻게 되냐에 다르겠지만, 대부분은 1번을 선택 할 것입니다. 

 

오류 가능성이 있는 연산이 수행되었을 때,

오류가 발생하게 되면, 오류 발생 이전의 객체 상태로 오류 발생 이후의 상태는 동일해야 한다. => 예외 안정성

 

아래 코드는 append를 하다가 예외가 발생합니다. 과연 어떤 결과가 나올까요?

enum LogError:Error {
    case invalidValue
}

struct Log {
    var values:[String]  = [String]()
    
    mutating func append(messages:[String]) throws {
        for message in messages {
            let trimmed = message.trimmingCharacters(in: .whitespacesAndNewlines)
            
            if trimmed.isEmpty {
                throw LogError.invalidValue
            }
            values.append(message)
        }
    }
}

var log = Log()
do {
    try log.append(messages: ["Hello World", "        ", "show me the money"])
} catch {
    print(error)
}
print(log)

 

결과

invalidValue

Log(values: ["Hello World"])

 

오류 나기 전까지만 더 해져있습니다. 

 

1. 임시 값을 이용하는 방법 , 최종 연산이 된 후에 값이 변경되게 해야됩니다. (복사본 이용)

    mutating func append(messages:[String]) throws {
        var temp = values
        for message in messages {
            let trimmed = message.trimmingCharacters(in: .whitespacesAndNewlines)
            
            if trimmed.isEmpty {
                throw LogError.invalidValue
            }
            temp.append(message)
        }
        values = temp
    }

 

2. defer block을 이용하는 방법

- 예외가 발생했을 때, 기존 Data를 defer block에서 지워버리는 방법입니다.

func writeToFiles(data:[URL:String]) throws {
    var completed = [URL]()
    
    //defer block에서는 defer밖으로 Error를 던질 수 없다.
    //try! - 예외가 발생 했을 경우 프로그램 강제 종료
    defer {
        if completed.count != data.count {
            //예외가 발생하면 이전 data를 모두 지우자
            print("예외가 발생했습니다. - \(completed)")
            for url in completed {
                // 1) try! removeItem을 해보면서 예외가 발생하면 프로그램 강제 종료
                
                //try! FileManager.default.removeItem(at: url)
                
                // 2) removeItem에 대한 예외처리
                do {
                    try FileManager.default.removeItem(at: url)
                } catch {
                    print("복구할 수 없는 오류 발생")
                }

            }
        }
    }
    for (url, contents) in data {
        try contents.write(to: url, atomically: true, encoding: .utf8)
        completed.append(url)
    }
}

do {
    try writeToFiles(data: [URL(fileURLWithPath: "/Users/hy/Desktop/a.txt"):"hello world"])
    try writeToFiles(data: [URL(fileURLWithPath: "~/b.txt"):"hello world"])
    try writeToFiles(data: [URL(fileURLWithPath: "/Users/hy/Desktop/c.txt"):"hello world"])
} catch {
    print(error)
}

3. 불변 객체를 사용하는 방법 

- 불변 객체를 사용해서 조건 검사후 새로운 객체를 만들면 됩니다.

enum UserError : Error {
  case invalidAge
}

struct User {
  let name: String
  let age: Int

  func child(childAge: Int) throws -> User {
    if age <= childAge {
      throw UserError.invalidAge
    }
    
    return User(name: "JR.\(name)" , age: childAge)
  }
}

let user = User(name: "Tom", age: 42)
print(user)
do {
  let jr = try user.child(childAge: 50)
  print(jr)
} catch {
  print(error)
}
print(user)