Assertion
assert(_:_file:line:) 함수를 사용한다.
assert 함수는 디버깅 모드에서만 동작한다.
배포하는 애플리케이션에서는 제외된다.
예상했던 조건의 검증을 위하여 사용한다.
다음과 같이 사용해볼 수 있다.
var someInt: Int = 0
assert(someInt == 0, "someInt != 0")
// 확인을 위해 someInt 의 값을 1로 변경
someInt = 1
assert(someInt == 0, "someInt != 0")
========== 출력 결과 ==========
Assertion failed: someInt != 0: file __lldb_expr_33/study23.playground, line 8
검증에 실패했고 실패한 메시지가 나타나고 file과 몇 번째 줄인지 순서대로 출력된 것을 확인할 수 있었다.
그리고 assertionFailure() 함수를 사용해서 assert() 의 조건이 실패한 것처럼 동작시킬 수 있다.
if someInt == 1 {
assertionFailure("assertionFailure")
}
========== 출력 결과 ==========
Fatal error: assertionFailure: file __lldb_expr_37/study23.playground, line 12
assert() 함수를 간단하게 사용해보았다.
func functionWithAssert(age: Int?) {
assert(age != nil, "age == nil")
assert((age! >= 0) && (age! <= 130), "나이값 입력이 잘못되었습니다.")
print("당신의 나이는 \(age!)세 입니다.")
}
functionWithAssert(age: 28)
========== 출력 결과 ==========
당신의 나이는 28세 입니다.
이런 식으로 디버깅할 수 있다.
추가적으로,
테스트를 작성할 때 필수일 뿐만 아니라 코드를 더 쉽게 디버깅이 가능하고 예측가능한 코드를 작성하기 위해 사용한다.
그래서 Assertion 은 코드가 실행될 때 반드시 만족해야 하는 조건을 코드 상에 명시해 놓는 것 이라고 한다.
Assertion 을 사용했을 때 조건에 만족하지 않는다면 문제가 발생할 것이고 어디에서 문제가 발생한 것인지
알 수 있기 때문에 디버깅이 더 쉬워질 수 있다는 것이다.
Assert() 와 비슷한 용도로 사용하는 함수인 precondition() 도 있다.
precondition 의 경우 디버깅 환경뿐만 아니라 릴리즈 환경에서도 사용한다는 차이가 있다.
따라서 배포하는 애플리케이션에서 assert() 함수를 대신해서 사용할 수 있다.
다시 정리해보자면
assert(), assertionFailure() 함수는 디버깅 모드에서만 동작한다.
precondition(), preconditionFailure() 함수는 디버깅 모드와 릴리즈 모드에서 동작한다.
guard (빠른 종료 - Early Exit)
guard를 사용하여 잘못된 값의 전달 시 특정 실행 구문을 빠르게 종료
디버깅 모드 뿐만 아니라 어떤 조건에서도 동작한다.
guard의 else 블럭 내부에는 특정 코드 블럭을 종료하는 지시어(return, break 등)가 꼭 있어야 한다.
타입 캐스팅, 옵셔널과 자주 사용된다.
단순 조건 판단 후 빠르게 종료할 때 용이하다.
다음과 같이 사용해보았다.
func funcGuard(age: Int?) {
guard let unwrappedAge = age,
unwrappedAge < 130,
unwrappedAge >= 0 else {
print("나이값 입력이 잘못되었습니다.")
return
}
print("당신의 나이는 \(unwrappedAge)세 입니다.")
}
funcGuard(age: 28)
funcGuard(age: 140)
========== 출력 결과 ==========
당신의 나이는 28세 입니다.
나이값 입력이 잘못되었습니다.
그리고 단순 조건일 경우 다음과 같이 사용해볼 수 있었다.
var count = 1
while true {
guard count < 3 else {
break
}
print(count)
count+=1
}
========== 출력 결과 ==========
1
2
if let 과 guard let 는 어떻게 다른가?
우선, if let 구문부터 확인해보자.
// if let 구문
func iflet() {
var someValue: Int?
someValue = 3
if let unwrapped: Int = someValue {
print(unwrapped)
}
// if let 구문 밖에서 사용할 수 없다.
print(unwrapped)
}
iflet()
=========== 에러 메시지 ==========
error: study23.playground:82:11: error: cannot find 'unwrapped' in scope
print(unwrapped)
^~~~~~~~~
if let 구문에서 unwrapped 라는 상수를 선언해주고 값을 지정해주었다.
밖에서 unwrapped 를 사용하려고 하니 아래와 같은 에러 메시지가 나왔다.
따라서 옵셔널 바인딩 된 상수는 if let 구문 안에서만 사용할 수 있다는 것이다.
그럼 다음으로 guard let 구문을 확인해보자.
// guard let 구문
func guardlet() {
var someValue: Int?
someValue = 3
guard let unwrapped: Int = someValue else {
return
}
print("gurad let \(unwrapped)")
}
guardlet()
=========== 출력 결과 ==========
guard let 3
if let 구문과 다르게 guard let 구문 안에서 지정해준 상수를 함수 내부에서 사용할 수 있는 것을 볼 수 있다.
즉, guard let 구문에서 옵셔널 바인딩 된 상수를 함수 내부의 지역 상수처럼 사용할 수 있다는 것이다.
그리고 if let 구문은 따로 else 를 사용하지 않아도 되지만 guard let 구문은 else 구문이 따라와야한다.
그리고 코드 블록 종료 시 코드 블록을 종료하는 지시어가 반드시 있어야 한다. (return, break, continue 등)
각 구문에 대해서 확인해보았는데
guard 를 사용하면 if 보다 훨씬 더 간결하게 사용할 수 있었다.
복잡한 조건이 아닌 예외 사항에 대한 처리를 하고 싶다면 guard 를 사용하는 것이 훨씬 좋을 것이다.
assert 와 guard 에 대해서 공부해봤는데
예전에 무작정 앱을 만드려고 따라하면서 보았던 부분들을 간단하게 다루어 보았다.
자세하게 이해는 했다고 할 수 없지만 그래도 어떤 것이구나 하는 정도는 알게 된 것 같다.
guard let 의 경우 여러 예제를 따라해보면서 많이 써본 것 같다.
그런데 assert 는 사실 한 번도 제대로 사용해본 적이 없는 것 같다.
공부하면서 느낀 건 assert 함수를 잘 사용하면 보다 쉽게 코드 관리를 할 수 있겠다는 생각이 들었고
테스트 코드가 중요하다는 글도 많이 보았고 나중에 테스트 코드를 작성하면서 사용해봐야겠다.
- 참고 사이트 -
www.edwith.org/boostcamp_ios/lecture/11313
pilgwon.github.io/blog/2017/09/25/Under-the-Hood-of-Assertions-in-Swift.html
seorenn.blogspot.com/2016/05/swift-assertion.html
velog.io/@dev-lena/guard-let과-if-let의-차이점
'iOS > Swift' 카테고리의 다른 글
[Swift] 25. 델리게이션(delegation), 델리게이트 패턴 공부 (0) | 2020.12.03 |
---|---|
[Swift] 24. 프로토콜 (protocol) (0) | 2020.12.03 |
스위프트는 어떻게 동작할까? (0) | 2020.11.25 |
[Swift] 22. 타입 캐스팅 (type casting) (0) | 2020.11.25 |
[Swift] 21. 옵셔널 체이닝과 nil 병합 (0) | 2020.11.18 |