iOS/Swift

콜백 함수는 언제 쓰이나요?

밤새는 탐험가89 2024. 8. 23. 12:00

콜백 함수는 주로 비동기 작업을 처리할 때 사용됩니다. 비동기 작업은 실행되는데 시간이 걸리거나, 언제 완료될지 알 수 없는 작업들을 의미해요. 예를 들어, 네트워크 요청, 파일 읽기/쓰기, 타이머, 애니메이션 등이 이에 해당합니다. 이러한 작업들이 완료된 후 특정 작업을 수행해야 할 때, 콜백 함수를 사용해 그 작업이 완료된 후의 행동을 정의할 수 있어요.

 

 

콜백 함수가 주로 쓰이는 상황

 

네트워크 요청

  • 서버에서 데이터를 가져오거나, 데이터를 서버에 보낼 때, 네트워크 요청은 시간이 걸리기 때문에 요청이 완료된 후에 데이터를 처리하는 콜백 함수를 사용합니다.
func fetchDataFromServer(completion: @escaping (Data?) -> Void) {
    // 비동기 네트워크 요청
    DispatchQueue.global().async {
        let data = ... // 서버에서 데이터 가져오기
        DispatchQueue.main.async {
            completion(data) // 요청 완료 후 콜백 호출
        }
    }
}

fetchDataFromServer { data in
    if let data = data {
        print("서버에서 데이터를 받았습니다: \(data)")
    } else {
        print("데이터를 가져오는 데 실패했습니다.")
    }
}

 

파일 입출력

  • 파일을 읽거나 쓰는 작업도 시간이 걸릴 수 있기 때문에, 작업이 완료된 후에 콜백을 사용해 결과를 처리합니다.
func readFileAsync(completion: @escaping (String?) -> Void) {
    DispatchQueue.global().async {
        let content = ... // 파일 읽기
        DispatchQueue.main.async {
            completion(content) // 파일 읽기 완료 후 콜백 호출
        }
    }
}

readFileAsync { content in
    if let content = content {
        print("파일 내용을 읽었습니다: \(content)")
    } else {
        print("파일을 읽는 데 실패했습니다.")
    }
}

 

 

타이머

  • 일정 시간이 지난 후에 특정 작업을 실행해야 할 때, 타이머와 콜백 함수를 사용할 수 있습니다.
func startTimer(duration: TimeInterval, completion: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
        completion() // 타이머 완료 후 콜백 호출
    }
}

startTimer(duration: 3.0) {
    print("3초가 지났습니다!")
}

 

 

애니메이션

  • 애니메이션이 끝난 후에 후속 작업을 처리하기 위해 콜백 함수를 사용합니다.
UIView.animate(withDuration: 1.0, animations: {
    // 애니메이션 작업
}, completion: { finished in
    if finished {
        print("애니메이션이 완료되었습니다.")
    }
})

 

 

콜백 함수의 장점

  • 비동기 작업의 결과를 처리: 콜백 함수를 사용하면 작업이 완료된 후에 특정 작업을 쉽게 처리할 수 있어요.
  • 코드의 가독성 향상: 콜백 함수를 사용하면 복잡한 비동기 작업의 흐름을 더 직관적으로 표현할 수 있습니다.
  • 유연성: 콜백 함수는 함수의 인자로 전달되기 때문에, 다양한 상황에 맞춰 동작을 쉽게 변경할 수 있어요.

 

정리

  • 콜백 함수는 주로 비동기 작업(네트워크 요청, 파일 입출력, 타이머, 애니메이션 등)에서 작업이 완료된 후의 행동을 정의하는 데 사용됩니다.
  • 이를 통해 비동기 작업이 완료된 후에 적절한 후속 작업을 수행할 수 있으며, 코드의 가독성과 유연성을 높일 수 있습니다.

 

 

비동기 작업과 콜백 함수의 역할

 

fetchData 함수가 비동기 작업을 한다고 가정했을 때, print("데이터 가져오는 중...")이 출력된 후 실제 데이터를 가져오는 작업이 완료되면 콜백 함수가 호출됩니다. 이때 콜백 함수 내부의 코드(print("데이터를 가져왔어!"))가 실행되는 거죠.

 

비동기 작업의 특징은, 작업이 끝나는 시간이 언제인지 정확히 예측할 수 없다는 점입니다. 네트워크 요청처럼 시간이 오래 걸리거나 언제 끝날지 모르는 작업이 있는 경우, 이 작업이 완료되기 전에 다음 코드를 실행하지 않도록 콜백 함수를 사용하는 거예요.

 

왜 fetchData 메서드 안에 다 넣지 않을까?

 

fetchData 메서드 안에 모든 코드를 넣을 수도 있지만, 콜백 함수를 사용하는 이유는 코드의 유연성을 높이기 위해서입니다. 콜백 함수를 사용하면 fetchData 함수가 완료된 후에 어떤 작업을 수행할지를 호출하는 쪽에서 자유롭게 정의할 수 있기 때문이죠.

 

예를 들어, fetchData를 호출하는 여러 곳에서 서로 다른 후속 작업을 수행해야 한다고 해볼게요. 콜백 함수 없이 모든 후속 작업을 fetchData 함수 내부에 넣으면, 그 작업들을 고정된 방식으로만 수행해야 합니다.

 

예시: 콜백 함수가 없는 경우

만약 fetchData 함수 안에 모든 후속 작업을 넣는다면, 다음과 같이 고정된 행동을 해야 합니다.

 

func fetchData() {
    print("데이터 가져오는 중...")
    // 데이터 가져오는 비동기 작업 (가정)
    print("데이터를 가져왔엉!")
}

// 호출
fetchData()

 

 

이 방식의 단점은 fetchData 함수가 항상 "데이터를 가져왔엉!"이라는 메시지를 출력해야 한다는 점이에요.

만약 다른 작업을 하고 싶다면 이 함수 자체를 수정해야 하죠.

 

예시: 콜백 함수가 있는 경우

콜백 함수를 사용하면 호출하는 쪽에서 어떤 작업을 할지 정할 수 있습니다.

func fetchData(completion: () -> Void) {
    print("데이터 가져오는 중...")
    // 데이터 가져오는 비동기 작업 (가정)
    completion()
}

// 호출 1: 데이터를 가져온 후 메시지 출력
fetchData {
    print("데이터를 가져왔엉!")
}

// 호출 2: 데이터를 가져온 후 다른 작업 수행
fetchData {
    print("데이터를 저장했엉!")
}

 

 

이 방식의 장점은 fetchData 함수가 호출되는 곳마다 그 후속 작업을 다르게 정의할 수 있다는 점이에요.

코드의 유연성과 재사용성이 높아집니다.

 

결론

  • 콜백 함수를 사용하면 비동기 작업이 끝난 후 어떤 작업을 수행할지를 호출하는 곳에서 정의할 수 있어, 코드가 더 유연하고 재사용이 가능해집니다.
  • 만약 fetchData 함수 안에 모든 작업을 넣으면, 모든 후속 작업이 고정되어 버려 다른 동작을 하려면 함수 자체를 수정해야 합니다.
  • 콜백 함수는 비동기 작업에서 후속 작업을 처리하기 위한 중요한 도구입니다.