Swift Concurrency를 적용하면서 발생한 동시성 문제
사내에서도 동일한 이슈가 발생했었어서 해당 부분에 대해서 정리하고자 함.
기존 Combine으로 작성된 코드를 async-await으로 교체하는 작업을 진행.
글의 순서
- Combine으로 작성된 코드 살펴보기
- Swift Concurrency로 단계적으로 전환하기
- Swift Concurrency로 안전성 확보하기
- Combine에서 Swift Concurrency 적용
Combine으로 작성된 코드 살펴보기
기존 코드는 캐싱을 위해 캐시 프로퍼티가 존재하며, Combine을 기반으로 작성되어 있었음.
- Combine을 선택한 이유는 RxSwift가 익숙하여, RxSwift와 닮은 애플 퍼스트파티 선택에서 Combine을 선택
Swift Concurrency로 단계적으로 전환하기
레포지토리에 async 인터페이스 추가
asnyc을 메소드에서 Result로 반환하는 이유
- Swift 6에서 부터는 throw에 에러 타입을 지정할 수 있으나, 그 이전 버전에서는 사용할 수 없음.
- 기존 프로젝트를 Swift 6로 마이그레이션 하는데 시간이 걸리기 때문에 Swift 5.10 기준으로 작업을 위해 Result로 반환
UseCase에도 async 인터페이스 추가
useCase에도 동일하게 추가해서 구현.
위의 코드에서는 불완전한 부분이 존재
외부 상황에 따라 매칭 부분이 동작하는 cache 프로퍼티가 읽기/쓰기 상황에 대한 데이터 경합이 발생하여 동시성 문제가 발생할 수 있음.
즉, cache 값이 데이터 경합 상황에서 안전하지 않음.
Swift Concurrency로 안전성 확보하기
데이터 경합 상황에 대한 안전성을 확보하기 위해 아래의 작업을 진행
- `class`에서 `actor`로 변경
- `actor` 변경함에 따라 UseCase 프로토콜을 개선
- 향후 사용하지 않게 되면 삭제하면 좋고, SDK로 제공하는 서비스라면 버전에 따라 deprecated 혹은 unavailable 처리
- Combine을 사용하는 곳은 Future + Task 조합을 활용하여 안전성 확보
- 구현체는 새로 사용하는 한곳을 바라보도록 개선
해당 방법 외에 다른 방법은 어떤게 있을까?
- 딕셔너리를 Swift에서 지원하는 타입이 아닌 actor 방식으로 동작할 수 있는 나만의 딕셔너리를 만들어서 사용할 경우 class로도 충분히 안정적으로 사용할 수 있음.
- 다만, actor로 swift에서 지원해주고 있어서 actor로 변경하는게 더 낫다고 판단됨.
Combine에서 Swift Concurrency 적용
사용부는 아래처럼 달라짐.
'iOS프로젝트 > Funch(넥스터즈)' 카테고리의 다른 글
모듈화 리팩토링 과정에서 고민했던 것들 (2) | 2024.09.24 |
---|---|
SwiftUI 화면 dismiss 상황에서 흰 화면 나타나는 문제 (1) | 2024.09.22 |
지하철 검색 기능에 캐싱 로직 도입하기 (0) | 2024.09.20 |
[IT 동아리 Nexters] 24기 프로젝트 회고 (0) | 2024.03.03 |
[iOS] Memory Debug Graph 분석해 프로젝트 구조 개선 (0) | 2024.03.01 |