함수를 선언할때 사용하는 파라미터의 경우, 기본적으로 값타입 이며, ‘임시 상수’ 이기 때문에, 함수 내에서 변경이 불가능하다.
func swap(a: Int, b: Int){
let temp = a
a = b
b = temp
} // (잘못된 코드)
따라서 위와 같은 표현을 사용해 두개의 파라미터를 받아서 파라미터의 값을 서로 바꾸는 함수를 작성할수는 없다.
이처럼 일반적으로 함수 내에서 파라미터의 값을 변경 불가능하지만, in-out 파라미터를 사용하면 가능해진다.
함수를 사용해서 입력되는 값을 직접 수정하고 싶을 때 사용하는 파라미터 이며, 파라미터의 데이터를 값 타입이 아닌 참조타입 으로 전달하기 때문에, 함수 내에서 파라미터 값에 직접 접근하여, 변경이 가능하다.
구현 방식은, 파라미터 이름 앞 (아규먼트 레이블이 있다면 그 앞)에 inout
키워드를 붙이는 것이다.
func swap(inout a: Int, inout b: Int){
let temp = a
a = b
b = temp
}
// inout 파라미터는 참조 타입이기 때문에, 함수 호출할때, 아규먼트 앞에 & 붙여준다.
var c = 5
var d = 7
swap(a: &c, b: &d)
위 코드처럼 swap
함수의 선언 시, 파라미터 앞에 in-out 키워드를 붙여줌으로서, 직접 파라미터에 접근해 값을 변경하는 것이 가능해졌다. 또한, inout 파라미터를 가진 함수를 호출할 때에는, 해당 파라미터가 참조타입 이므로, 반드시 아규먼트 앞에 앰퍼센트 기호 (&) 를 붙여준다.
in-out 파라미터를 사용할 때는 다음과 같은 점을 주의한다.
guard 문은 Swift 에만 있는 조건문으로, 기본적으로는 if 문과 같은 기능을 수행한다.
guard 문은 if 문과는 다르게, 해당 조건을 만족하지 않을 경우 스코프 안의 구문이 실행된 후, 해당 구문이 조기 종료되는 형식으로 구현된다.
guard {조건} else {예외시 코드+조기종료}
형식으로, 조건을 만족하지 못하면 무조건 조기종료 (Early Exit) 될 수 있도록 한다.if문을 중첩해서 사용하는 경우, 스코프 안에 계속해서 코드를 들여써야 한다는 점이 불편한데, guard문은 이러한 단점을 보완한다는 장점이 있다.
예를 들어, 정수가 2의 배수이자, 4의 배수, 그리고 8의 배수인지 쭉쭉 확인하는 코드를 구현한다고 할때, if 문으로 구현하면
func checkNum(num:Int){
if num%2 == 0{
print("2의 배수")
if num%4 == 0 {
print ("4의 배수")
if num%8 == 0 {
print("8의 배수")
}
}
}
else {
print("짝수 아님")
}
}
이처럼 중첩되는 if 문으로 구현하는 기능의 경우, 지속적으로 들여쓰기를 해줘야하는 불편함이 생기는데
func checkNum2(num:Int){
guard num%2 == 0 else {
print("짝수 아님")
return
}
print("2의 배수")
guard num%4 == 0 else {
return
}
print("4의 배수")
guard num%8 == 0 else {
return
}
print("8의 배수")
}
이처럼 guard문을 사용해서 같은 기능을 구현해주면, 더 가독성이 좋아진다.
return
, throw
)으로 완결한다. (guard body must not fallthrough!)attribute 키워드는 컴파일러에게, 직접 특정 대상에 대한 추가적인 정보를 제공하는 키워드로, ‘@’ 키워드를 앞에 붙여서 사용한다. attributes 키워드는 크게 아래와 같은 두가지 타입이 있다.
@available(iOS 13.10, *) // iOS 버전을 지정
class Myclass {
// 코드
}
func doSomth(completion:@escaping()->()){
// 코드
}
Swift에는 대표적으로 다음과 같은 attributes 키워드들이 있다.
그중, @discardableResult의 경우, 함수 앞에 사용해 주는 attributes 키워드인데, 해당 함수의 리턴값을 사용하지 않더라도 컴파일러가 경고창(노란색)을 보여주지 않게 하는 역할을 한다.
@discardableResult
func doDiscardResult()->String {
print("함수의 동작 구현")
return "Discard this result" // 함수의 리턴값.
}
doDiscardableResult()
위 코드와 같이 @discardableResult와 함께 선언된 함수를 호출하면, 리턴값은 사용하지 않고, 동작만 수행하게된다.