Swift에서 'Hashable' 프로토콜을 준수하지 않는 문제 해결하기!
Swift에서 Async/Await 사용법: 비동기 프로그래밍의 혁신
Swift 5.5에서는 비동기 작업을 처리하는 새로운 방식인 async
/await
를 도입했습니다. 이 기능은 비동기 코드 작성을 더욱 직관적이고 가독성 있게 만들어줍니다. 이 글에서는 async
/await
의 기본 개념부터 실용적인 예제까지, Swift에서 비동기 프로그래밍을 효율적으로 처리하는 방법을 자세히 설명합니다.
1. Async/Await의 기본 개념
async
/await
는 비동기 코드를 작성하는 새로운 방법으로, 기존의 콜백 기반 접근 방식보다 더 명확하고 유지 보수하기 쉬운 코드를 작성할 수 있게 해줍니다. 비동기 함수는 async
키워드를 사용하여 정의되며, 비동기 호출은 await
키워드를 사용하여 수행됩니다.
Async 함수 정의
비동기 함수는 async
키워드를 사용하여 정의됩니다. 예를 들어, 데이터를 비동기적으로 가져오는 함수를 다음과 같이 정의할 수 있습니다.
swiftimport Foundation func fetchData(from url: String) async throws -> Data { guard let url = URL(string: url) else { throw URLError(.badURL) } let (data, _) = try await URLSession.shared.data(from: url) return data }
위 함수는 URL에서 데이터를 비동기적으로 가져오며, await
키워드를 사용하여 URLSession의 data(from:)
메서드를 호출합니다.
Await를 사용한 비동기 함수 호출
비동기 함수는 await
키워드를 사용하여 호출됩니다. 예를 들어, fetchData
함수를 호출하는 코드는 다음과 같습니다.
swiftTask { do { let data = try await fetchData(from: "https://example.com") print("Data received: \(data)") } catch { print("Failed to fetch data: \(error)") } }
Task
는 비동기 코드를 실행하는 컨텍스트를 제공합니다.
2. Async/Await의 장점
async
/await
는 여러 가지 장점을 제공합니다.
- 가독성 향상: 코드가 동기 코드와 유사하게 보이기 때문에 가독성이 향상됩니다.
- 에러 처리 간소화:
do
/try
/catch
를 사용하여 비동기 함수의 에러를 쉽게 처리할 수 있습니다. - 콜백 지옥 방지: 중첩된 콜백 대신 직관적인 방식으로 비동기 작업을 체인화할 수 있습니다.
3. 실용적인 예제
네트워킹 예제
async
/await
를 사용하여 API 호출을 처리하는 예제를 살펴보겠습니다.
swiftimport Foundation struct Post: Decodable { let id: Int let title: String let body: String } func fetchPosts() async throws -> [Post] { let url = URL(string: "https://jsonplaceholder.typicode.com/posts")! let (data, _) = try await URLSession.shared.data(from: url) let posts = try JSONDecoder().decode([Post].self, from: data) return posts } Task { do { let posts = try await fetchPosts() for post in posts { print("Title: \(post.title)") } } catch { print("Failed to fetch posts: \(error)") } }
위 코드는 JSONPlaceholder API에서 게시물을 가져와 디코딩한 후, 제목을 출력합니다.
데이터베이스 접근 예제
비동기 작업은 데이터베이스 접근에서도 유용합니다.
swiftimport CoreData func fetchUsers() async throws -> [User] { let fetchRequest: NSFetchRequest<User> = User.fetchRequest() return try await withCheckedThrowingContinuation { continuation in do { let users = try context.fetch(fetchRequest) continuation.resume(returning: users) } catch { continuation.resume(throwing: error) } } } Task { do { let users = try await fetchUsers() for user in users { print("User: \(user.name)") } } catch { print("Failed to fetch users: \(error)") } }
위 코드는 Core Data를 사용하여 비동기적으로 사용자 데이터를 가져옵니다.
4. Async/Await와 Combine 사용
Combine 프레임워크와 async
/await
를 결합하여 비동기 작업을 처리할 수도 있습니다.
swiftimport Combine func fetchDataPublisher(from url: String) -> AnyPublisher<Data, URLError> { guard let url = URL(string: url) else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } return URLSession.shared.dataTaskPublisher(for: url) .map(\.data) .eraseToAnyPublisher() } Task { do { let data = try await fetchDataPublisher(from: "https://example.com") .async() print("Data received: \(data)") } catch { print("Failed to fetch data: \(error)") } }
위 코드는 Combine 퍼블리셔를 async
/await
와 함께 사용하여 데이터를 비동기적으로 가져옵니다.
결론
Swift의 async
/await
는 비동기 코드를 더 직관적이고 관리하기 쉽게 만듭니다. 네트워킹, 데이터베이스 접근, Combine과의 통합 등 다양한 시나리오에서 유용하게 사용될 수 있습니다. 이를 통해 더욱 효율적이고 가독성 높은 코드를 작성할 수 있습니다.
더 많은 정보는 🔗 Apple Developer Documentation에서 확인할 수 있습니다.