[다양한 표현 및 확장] 13. assert, guard

Seoyoung Lee·2022년 2월 24일
0


2021년 12월 31일에 공부한 내용입니다.


assert와 guard를 이용하여 애플리케이션이 동작 도중에 생성하는 다양한 결과값을 동적으로 확인하고 안전하게 처리할 수 있도록 확인하고 빠르게 처리할 수 있다.

1. Assertion

  • assert(_:_:file:line:) 함수를 사용한다.
  • assert 함수는 디버깅 모드에서만 동작한다.
  • 배포하는 애플리케이션에서는 제외된다.
  • 예상했던 조건의 검증을 위하여 사용한다.
var someInt: Int = 0

assert(someInt == 0, "someInt != 0")

someInt = 1
// assert(someInt == 0) // 동작 중지, 검증 실패
// assert(someInt == 0, "someInt != 0") // 동작 중지, 검증 실패
// assertion failed: someInt != 0: file guard_assert.swift, line 26

func functionWithAssert(age: Int?) {
    assert(age != nil, "age == nil")

    assert((age! >= 0) && (age! <= 130), "나이값 입력이 잘못되었습니다")
    print("당신의 나이는 \(age!)세입니다")
}

functionWithAssert(age: 50)
//functionWithAssert(age: -1) // 동작 중지, 검증 실패
//functionWithAssert(age: nil) // 동작 중지, 검증 실패

* assert(_:_:file:line:)와 같은 역할을 하지만 실제 배포 환경에서도 동작하는 precondition(_:_:file:line:) 함수도 있다.


2. guard(빠른 종료 - Early Exit)

  • guard를 사용하여 잘못된 값의 전달 시 특정 실행구문을 빠르게 종료한다.
  • 디버깅 모드 뿐만 아니라 어떤 조건에서도 동작한다.
  • guardelse 블럭 내부에서는 특정 코드블럭을 종료하는 지시어(return, break 등)가 꼭 있어야 한다.
  • 타입 캐스팅, 옵셔널과도 자주 사용된다.
  • 그 외에도 단순 조건 판단 후 빠르게 종료할 때도 용이하다.
func functionWithGuard(age: Int?) {
    guard let unwrappedAge = age, // 옵셔널 바인딩 먼저 실행
        unwrappedAge < 130,
        unwrappedAge >= 0 else {
        print("나이값 입력이 잘못되었습니다")
        return
    }
    /*
    guard unwrappedAge < 100 else {
        return
    }

    if unwrappedAge < 100 {

    } else {
        return
    }
    */
    print("당신의 나이는 \(unwrappedAge)세입니다")
}

var count = 1

// 반복문 내에서도 사용 가능
while true {
    guard count < 3 else {
        break
    }
    print(count)
    count += 1
}
// 1
// 2

// 딕셔너리를 받아올 때 많이 사용한다
func someFunction(info: [String: Any]) {
    guard let name = info["name"] as? String else { // value가 Any이기 때문에 String으로 캐스팅을 시도함
        return
    }
    guard let age = info["age"] as? Int, age >= 0 else {
        return
    }
    print("\(name): \(age)")
}

someFunction(info: ["name": "jenny", "age": "10"])
someFunction(info: ["name": "mike"])
someFunction(info: ["name": "seoyoung", "age": 10]) // seoyoung: 10

* if let/guard를 이용한 옵셔널 바인딩 비교

// 1. if let 옵셔널 바인딩
if let unwrapped: Int = someValue {
    // do something
    unwrapped = 3
}
// if 구문 외부에서는 unwrapped 사용이 불가능하다.
// unwrapped = 5

// 2. guard 옵셔널 바인딩
// guard 구문 이후에도 unwrapped 사용이 가능하다.
guard let unwrapped: Int = someValue else {
    return
}
unwrapped = 3

💡 생각해보기

if 구문이 있는데 굳이 왜 guard 구문을 사용할까?

Using a guard statement for requirements improves the readability of your code, compared to doing the same check with an if statement. It lets you write the code that’s typically executed without wrapping it in an else block, and it lets you keep the code that handles a violated requirement next to the requirement.
(Swift 공식 문서 참조)

profile
나의 내일은 파래 🐳

0개의 댓글