본문 바로가기
⌨️ Language/swift

[Swift] 예외 처리와 함수

by hyebin (Helia) 2024. 3. 17.

1. 예외 처리

오류 처리의 개념

  • 프로그램에 에러가 발생했을 때, 이를 감지하고 복구하는 프로세스
  • 모든 프로그램이 항상 원하는대로 정확히 동작한다는 보장이 없기 때문에 오류가 발생할 수 있음을 항상 고려해야 함

guard

guard 조건 else {조건이 거짓일 때 실행될 구문}

// someValue 가 0이 아닐 경우에만 출력
guard someValue != 0 else { return }
print(someValue)
  • 조건들을 걸러낼 때 사용
  • 가독성을 위해 사용
    • 조건식에 이 함수가 수행하는데 필요한 조건을 그대로 적는다는 점에서 guard 구문이 코드를 분석할 때 가독성이 좋아짐
func printMessage(_ message: String?) {
	if message == nil { return }
    print(message!) // 이미 nil 검사를 했음!
}
printMessage(string)

func printMessage(_ message: String?) {
	guard message != nil else { return }
    print(message!)
}
printMessage(string)
  • 옵셔널 바인딩
    • guard를 사용하면 if 로 옵셔널 바인딩했을 때와 달리 { } 괄호 밖에서도 사용 가능
var string:String? = "hello"

func printMessage(_ message: String?) {
    guard let letMessage = message else { return }
    print(letMessage)
}
printMessage(string)

func printMessage(_ message: String?) {
    if let letMessage = message{
        print(letMessage)
    } else { return }
}
printMessage(string)

 

do-catch

  • throw
    • 오류 던지기(오류를 던진다 = 오류를 처리해주는 곳으로 전달해준다)
      1. throws는 오류가 발생할 가능성이 있는 메소드 제목 옆에 작성
      2. throw ( ‘s’ 없음)은 오류가 발생할 구간에 작성
func printNumber(_ number: Int)throws -> Int {
// 1   
var text = ""
   guard number > 0 else {
throw TestError.outOfRange 
// 2   
}    
return text
}
  • try
    • ‘이 함수가 오류가 발생할 수도 있는데, 한번 시도해볼게요.’
let resultNumber = try object.printNumber(-20)
  • do-catch
do {  
   let resultNumber = try object.printNumber(-20)
// 위의 함수가 오류이 함수가 오류가 발생할 수도 있는데, 한번 시도해볼게요.

} catch {
   print(error)
// 오류를 잡으면 error를 프린트합니다.
}

 

2.함수

함수의 정의

  • 함수는 특정 작업을 수행하기 위해 함께 구성된 일련의 명령문
  • 함수를 선언할 때는 func 키워드 사용
  • (n: Int) → Int 와 같은 형식으로 파라미터와 반환형을 정의
  • 파라미터와 반환 값은 모든 타입으로 선언 가능(Int, String, Bool, Array, optional…)
  • 파라미터는 let으로 변경 불가
/*
func 함수명 (파라미터: 데이터 타입) -> 반환타입 {
	return
}
*/

func add(n: Int) -> Int {
	return n+2
}

let result = add(n: 2)
print(result) //4

 

함수의 필요성

  1. 재사용성
    • 함수를 사용하면 동일한 코드를 반복해서 다시 작성하지 않고도 여러 번 재사용할 수 있는 코드를 작성할 수 있음
    • 복잡하거나 반복적인 작업을 처리할 때 많은 시간과 노력을 절약할 수 있음
  2. 모듈성
    • 함수는 복잡한 작업을 더 작고 관리하기 쉬운 코드 조각으로 분해하여 이해하고 유지 관리하기 쉬움
    • 코드를 모듈화하여 독립적으로 테스트하고 디버깅할 수 있는 별도의 구성 요소로 나눌 수 있음을 의미
  3. 추상화
    • 함수를 사용하면 작업의 구현 세부 사항을 추상화하고 작업을 수행하기 위한 고급 인터페이스를 제공할 수 있음
    • 구현 세부 사항에 익숙하지 않은 다른 개발자를 위해 코드를 더 읽기 쉽고 사용하기 쉽게 만듭니다.
  4. 캡슐화
    • 함수는 코드와 데이터를 캡슐화하는 데 도움이 됨
    • 즉, 작업의 구현 세부 정보를 숨길 수 있고 코드와 상호 작용하기 위한 공용 인터페이스만 노출할 수 있음
    • 의도하지 않은 부작용이나 코드의 다른 부분과의 상호 작용을 방지할 수 있음
  5. 코드 구성
    • 함수는 코드를 논리적 그룹으로 구성하여 코드를 더 쉽게 탐색하고 이해할 수 있도록 도와줌
    • 코드 중복을 방지하고 코드베이스의 전반적인 복잡성을 줄이는 데 도움이 될 수 있음

 

파라미터(Parameters)와 반환 값

  • 파라미터가 없는 함수
func sayHelloWorld() -> String {
 return "hello, world"
}
print(sayHelloWorld()) // hello, world
  • 여러개의 파라미터를 사용하는 함수
func add(a: Int, b: Int) -> Int {
 return a+b
}
print(add(a: 3, b: 4)) // 7
  • 반환 값이 없는 함수여러개의 값을 반환하는 함수 (튜플로 반환)
func calculator(a: Int, b: Int) -> (sum: Int, sub: Int) {
 return (a+b, a-b)
}

let result = calculator(a: 3, b: 4)
print(result.sum, result.sub) // (7, -1)

 

함수 인자 라벨과 파라미터 이름

  • 인자 라벨 지정: 함수 호출 시 사용할 파라미터 이름 지정
func printName(insertName name: String){
    print( "my Name is " + name + ".")  //my Name is hyebin.
}
 
printName(insertName: "hyebin")
  • 인자 생략: 파라미터 앞에 “_”를 붙여 함수 호출 시 파라미터 이름 생략
func printName(_ name: String, _ age: Int){
    print( name, age)  //hyebin 14
}
 
printName("hyebin" , 14)
  • 기본 파라미터 값
    • 함수의 파라미터에 기본 값을 설정
    • 기본값이 설정된 파라미터는 함수 호출 시 생략 가능
func printName(name: String, age: Int = 24){
    print( name, age)  //hyebin 24
}
 
printName(name: "hyebin")  //hyebin 24
printName(name: "yyy", age: 90)  //yyy 90
  • 가변 파라미터
    • 파라미터 데이터 타입 뒤에 ... 키워드 사용
    • 가변 파라미터 뒤에 있는 파라미터는 인자 생략 불가
    • 기본값을 가질 수 없으며, 하나의 파라미터에서만 사용 가능
    • 입력 값의 수가 사전에 알려지지 않고 런타임 시 달라질 수 있는 경우에 유용
    • 가변 파라미터로 전달된 값은 함수 내부의 배열로 수집
func avg(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
print(avg(1, 2, 3, 4, 5))  // 3.0
print(avg(3, 8.25, 18.75)) //10.0
  • 인-아웃 파라미터
    • 함수에서 직접 파라미터 값에 접근할 수 있도록 하는 파라미터 (파라미터를 var로 사용)
    • 함수의 인자에 변수를 넣을 때 & 키워드 사용
    • 함수 내부의 변수 값을 수정해야 하고 해당 변경 사항을 함수 외부에도 반영하고자 할 때 유용
    • in-out 매개변수는 변수에만 사용할 수 있음
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
 
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \\(someInt), and anotherInt is now \\(anotherInt)")
// someInt is now 107, and anotherInt is now 3

 

함수 타입

  • 모든 함수는 파라미터 형과(parameter types) 반환 형(return type)으로 구성된 특정한 함수 타입을 가짐
  • 변수 형으로
    • 변수 또는 상수 유형으로 사용 가능
    • 함수를 값으로 저장하고 나중에 호출 가능
    • 변수나 상수에 함수를 할당할 때 함수 형을 선언하지 않아도 타입 추론해 자동으로 함수 할당 가능
func addTwoInts(_ a: Int, _ b: Int) -> Int {
  return a + b
}
 
var mathFunction: (Int, Int) -> Int = addTwoInts
//var mathFunction = addTwoInts
 
print(mathFunction(2,3))//5
  • 파라미터 형으로
    • 함수에 대한 파라미터의 타입으로 사용 가능
    • 함수를 다른 함수의 인수로 전달할 수 있으며 전달된 함수를 호출 가능
func addTwoInts(_ a: Int, _ b: Int) -> Int {
  return a + b
}
 
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \\(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5) //"Result: 8"
  • 반환형으로
    • 함수의 반환 타입으로도 사용 가능
    • 함수에서 함수를 반환 가능
func stepForward(_ input: Int) -> Int {
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
 
while currentValue != 0 {
    print("\\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")

/*
3... 
2... 
1... 
zero!
*/

 

중첩함수

  • 중첩 함수는 내부 함수를 호출하여 외부 함수를 호출하는 기능을 제공
func calcDecrement(forDecrement total: Int) -> () -> Int {
    var overallDecrement = 0
    
    func decrementer() -> Int {
        overallDecrement -= total
        return overallDecrement
     }
    
    return decrementer
}

let decrem = calcDecrement(forDecrement: 30)
print(decrem()) // -30
  • 함수의 오버로딩(Overloading)
    • 함수 이름은 같지만 파라미터, 리턴타입 등을 다르게 하여 함수를 중복으로 선언
    • 같은 이름의 함수를 선언하면 오류 발생
    • 파라미터와 리턴타입을 다르게 하면 오류가 발생하지 않음
    • 같은 동작을 하지만 파라미터 타입, 리턴 타입이 다른 함수를 같은 이름으로 선언하여 코드를 직관적으로 작성 가능
func sum() { }
func sum() { }      // Invalid redeclaration of 'sum()'
func sum() { }
func sum(n: Int) { }
func sum() -> Int { return 0 }
// 모두 두 수를 더하는 동작을 하지만 타입에 따라 이름이 달라짐
func sumInt(_ a: Int, _ b: Int) -> Int {
    return a + b
}
 
func sumDouble(_ a: Double, _ b: Double) -> Double {
    return a + b
}
 
func sumString(_ a: String, _ b: String) -> String {
    return a + b
}

// sum으로 함수의 이름을 동일하게 하고, 파라미터와 리턴 값의 타입만 변경
func sum(_ a: Int, _ b: Int) -> Int {
    return a + b
}
 
func sum(_ a: Double, _ b: Double) -> Double {
    return a + b
}
 
func sum(_ a: String, _ b: String) -> String {
    return a + b
}

 

함수와 메서드의 차이

메서드: 함수를 호출하는 객체가 있는 경우 → a.remove()

함수: 함수를 호출하는 객체가 없는 경우 → func remvoe(), remove()

반응형

'⌨️ Language > swift' 카테고리의 다른 글

[Swift] 클래스와 구조체  (0) 2024.03.19
[Swift] 클로저  (1) 2024.03.18
[Swift] 조건/반복문  (1) 2024.03.17
[Swift] 콜렉션 타입  (0) 2024.03.16
[Swift] 변수와 프로퍼티2  (1) 2024.03.15

댓글