Swift 오류 처리 및 디버그 상세 정보

8665 단어

1. 표시 및 오류 던지기


Swift에서 오류는 Error 프로토콜 유형의 값으로 표시됩니다.이 빈 프로토콜은 오류 처리에 사용할 수 있는 형식을 표시합니다.Swift 매거는 관련 오류 조건을 모델링하는 데 특히 적합하며, 관련 값에 오류 성질의 추가 정보를 추가할 수 있습니다.
enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}

키워드throw를 사용하여 실행 중인 문장에서 잘못된 정보를 표시합니다.
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

2. 오류 처리


(1).던지기 함수로 오류 전파
  • 키워드throws를 사용하여 함수, 방법, 또는 구조기가 오류를 던질 수 있음을 나타낸다.
  • 함수 성명의 매개 변수 뒤에 throws를 추가하고 화살표 -> 이전으로 되돌려줍니다.
  • 던지기 함수가 실행되고 있는 것은 그 중 던지는 오류를 호출하는 범위로 전파하는 것이다.
  • func canThrowErrors() throws -> String
    
    함수를 던져야만 오류를 전파할 수 있다.throwing 함수가 아닌 오류는 함수 내부에서 처리해야 합니다.
    struct Item {
        var price: Int
        var count: Int
    }
    
    class VendingMachine {
        var inventory = [
            "Candy Bar": Item(price: 12, count: 7),
            "Chips": Item(price: 10, count: 4),
            "Pretzels": Item(price: 7, count: 11)
        ]
        var coinsDeposited = 0
    
        func vend(itemNamed name: String) throws {
            guard let item = inventory[name] else {
                throw VendingMachineError.invalidSelection
            }
    
            guard item.count > 0 else {
                throw VendingMachineError.outOfStock
            }
    
            guard item.price <= coinsDeposited else {
                throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
            }
    
            coinsDeposited -= item.price
    
            var newItem = item
            newItem.count -= 1
            inventory[name] = newItem
    
            print("Dispensing \(name)")
        }
    }
    
    vend(itemNamed: 방법 내부에서 오류를 처리하지 않고 던진 오류를 직접 전파한다.이 방법을 호출하는 다른 코드는 do-catch 문장, try?, try!, 또는 오류를 계속 전파하는 방식으로 처리해야 한다.
    let favoriteSnacks = [
        "Alice": "Chips",
        "Bob": "Licorice",
        "Eve": "Pretzels",
    ]
    func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
        let snackName = favoriteSnacks[person] ?? "Candy Bar"
        try vendingMachine.vend(itemNamed: snackName)
    }
    
    buyFavoriteSnack(person: vendingMachine:)도 던지기 함수로서 내부에서 호출된 vend(itemNamed: 방법은 오류를 낼 수 있기 때문에 방법 실행 앞에 키워드 try 를 추가하여 호출합니다.
    함수를 던지는 것과 같이 구조기를 던지는 것도 같은 방식으로 오류를 전파할 수 있다.
    struct PurchasedSnack {
        let name: String
        init(name: String, vendingMachine: VendingMachine) throws {
            try vendingMachine.vend(itemNamed: name)
            self.name = name
        }
    }
    

    (2).Do-Catch 처리 오류를 사용하여 코드 블록을 실행하여do-catch 문장으로 오류를 처리할 수 있습니다.do 패키지의 코드가 오류를 내면catch 패키지와 일치하여 오류를 처리할 수 있는지 확인합니다.
    do {
        try expression
        statements
    } catch pattern 1 {
        statements
    } catch pattern 2 where condition {
        statements
    } catch {
        statements
    }
    

    패키지를 닫으면 어떤 오류를 처리할 수 있는지를 표시하기 위해catch 다음에 처리할 오류 모드를 작성할 수 있습니다.만약catch 패키지가 일치하는 오류 모드가 없다면, 오류를 마지막catch 패키지에 맡기고 오류를 error라는 로컬 상수에 연결합니다.
    var vendingMachine = VendingMachine()
    vendingMachine.coinsDeposited = 8
    do {
        try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
        print("Success! Yum.")
    } catch VendingMachineError.invalidSelection {
        print("Invalid Selection.")
    } catch VendingMachineError.outOfStock {
        print("Out of Stock.")
    } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
        print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
    } catch {
        print("Unexpected error: \(error).")
    }
    // Prints "Insufficient funds. Please insert an additional 2 coins."
    

    위의 예에서 buyFavoriteSnack(person:vendingMachine:) 함수는 try 표현식에서 호출된다. 왜냐하면 그는 오류를 던질 수 있기 때문이다.오류가 발생했을 때, 즉시 상응하는catch 패키지로 돌아가서 오류를 처리합니다.오류가 없으면 do 패키지의 나머지 문장을 계속 실행합니다.
    이catch 패키지는 do 패키지의 코드가 던질 수 있는 모든 오류를 처리할 필요가 없습니다.catch 패키지 처리 오류가 없으면 오류가 주위 범위로 전파됩니다.그러나 전파의 오류는 주위의 어느 범위에서 처리해야 한다.비포맷 함수에서do-catch를 포함하는 패키지는 오류를 처리해야 합니다.던지기 함수에 do-catch 패키지를 포함하거나 호출자가 오류를 처리해야 합니다.오류가 처리되지 않고 최상위 범위로 전파되면 실행 중 오류가 발생합니다.
    func nourish(with item: String) throws {
        do {
            try vendingMachine.vend(itemNamed: item)
        } catch is VendingMachineError {
            print("Invalid selection, out of stock, or not enough money.")
        }
    }
    
    do {
        try nourish(with: "Beet-Flavored Chips")
    } catch {
        print("Unexpected non-vending-machine-related error: \(error)")
    }
    // Prints "Invalid selection, out of stock, or not enough money."
    

    (3).오류를 선택적 값으로 변환
    오류를 선택적 값으로 변환하여 오류를 처리할 수 있습니다try?.try? 표현식을 실행할 때 오류가 발생하면 표현식의 값은nil입니다.
    func someThrowingFunction() throws -> Int {
        // ...
    }
    
    let x = try? someThrowingFunction()
    
    let y: Int?
    do {
        y = try someThrowingFunction()
    } catch {
        y = nil
    }
    

    모든 오류를 같은 방식으로 처리하고 싶을 때, try? 를 사용하면 간결한 오류 처리 코드를 쓸 수 있습니다.다음 예에서 보듯이 모든 방법이 실패하면 nil로 돌아갑니다.
    func fetchData() -> Data? {
        if let data = try? fetchDataFromDisk() { return data }
        if let data = try? fetchDataFromServer() { return data }
        return nil
    }
    

    (4).오류 전파를 사용하지 않습니다. 때때로 함수나 방법이 실행될 때 오류를 던지지 않는다는 것을 알고 있습니다.이 경우 표현식 앞에 try! 을 추가하여 오류의 전파를 금지하고 호출 포장을 실행할 때 오류가 발생하지 않는다고 단언할 수 있습니다.실제 오류가 발생하면 실행 중 오류가 발생합니다.
    let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
    

    3. 정리 작업 지정

  • defer문장이 있는 코드 블록은 어떤 방식으로 실행을 끝내든(예를 들어 오류를 던지거나break 또는return문장) defer의 코드는 시종일관 실행되고 마지막으로 실행된다.
  • 여러 개의 defer 문장이 같은 코드 블록에 있을 때 실행되는 순서는 원본 코드에 기록된 순서와 상반된다(즉 원본 코드 순서의 마지막 defer 문장이 먼저 실행된다).예를 들어 defer 문장을 사용하여 파일 설명자를 닫고 수동으로 분배된 메모리를 방출합니다.
  • func processFile(filename: String) throws {
        if exists(filename) {
            let file = open(filename)
            defer {
                close(file)
            }
            while let line = try file.readline() {
                // Work with the file.
            }
            // close(file) is called here, at the end of the scope.
        }
    }
    

    4. 단언과 선결 조건

  • 단언과 선결 조건은 운행할 때 발생하는 검사이다.
  • 단언 또는 선결 조건의 볼 값이true이면 코드는 계속 정상적으로 실행됩니다.false이면 프로그램의 현재 상태가 잘못됩니다.코드 실행 종료, 응용 프로그램 종료.
  • 개발 과정에서 오류와 잘못된 가설을 발견할 수 있다고 단언한다.선결 조건은 생산 중의 문제를 검측할 수 있다.
  • 단언과 선결 조건은 상기 오류 처리에서 논의된 오류 조건과 달리 복구 가능하거나 예상된 오류에 사용되지 않는다.실패한 단언이나 선결 조건이 잘못된 프로그램 상태를 표시하기 때문에 실패한 단언을 포착할 수 없습니다.*단언과 선결 조건을 사용하여 유효한 데이터와 상태를 실행하면 프로그램이 무효 상태가 발생할 때 더욱 쉽게 종료되고 디버깅하기 쉽다.
  • 단언과 선결 조건 사이의 차이는 언제 그것들을 검사하는가에 있다. 단언은 디버깅 버전에서만 검사하고 선결 조건은 디버깅과 생산 버전에서 모두 검사한다.생산 버전에서는 단언의 조건을 평가하지 않습니다.이것은 개발 과정에서 임의의 수량의 단언을 사용할 수 있고 생산 중의 성능에 영향을 주지 않는다는 것을 의미한다.

  • (1).단언 디버깅을 사용하여 Swift 표준 라이브러리에서 assert(_:_:file:line:) 함수를 호출하여 단언을 작성합니다.이 함수에 전달된 표현식은 true 또는 false 입니다.조건의 결과가 false 이면 메시지가 표시됩니다.예:
    let age = -3
    assert(age >= 0, "A person's age can't be less than zero.")
    // This assertion fails because -3 is not >= 0.
    

    단언 메시지를 생략할 수 있습니다. 예를 들면:
    assert(age >= 0)
    

    코드가 조건을 검사했다면 assertionFailure (_:file:line:) 함수를 사용하여 단언이 실패했음을 표시합니다.예:
    if age > 10 {
        print("You can ride the roller-coaster or the ferris wheel.")
    } else if age > 0 {
        print("You can ride the ferris wheel.")
    } else {
        assertionFailure("A person's age can't be less than zero.")
    }
    

    (2).실행 선결 조건은 조건이 가짜일 수 있지만 코드를 계속 실행할 수 있도록 조건이 진실이어야 하며 선결 조건을 사용한다.precondition(_:_:file:line:) 함수를 호출하여 선결 조건을 작성할 수 있습니다.이 함수에 계산 결과가 진짜인지 가짜인지 표현식을 전달하고 조건 결과가 가짜일 때 메시지를 표시합니다.예:
    // In the implementation of a subscript...
    precondition(index > 0, "Index must be greater than zero.")
    

    실패가 발생했을 때 preconditionFailure(_:file:line:) 함수를 호출할 수도 있습니다. 예를 들어 스위치의 기본 상황을 선택했지만 모든 유효한 입력 데이터는 스위치의 한 가지 상황에 의해 처리되어야 합니다.

    5. 치명적인 오류

  • 지정된 오류 메시지를 무조건 내보내고 실행을 중지합니다.
  • //message:  
    //file:  “message” 
    //line: “message” 
    public func fatalError(_ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) -> Never
    

    6. 기타 테마 모듈


    Swift 4.2 기본 주제 상세 정보

    좋은 웹페이지 즐겨찾기