Task.isCancelled, 어디서 체크해야 진짜 안전할까

들어가며비동기 화면을 구현하다 보면 이런 문제를 자주 만난다.사용자가 리스트에서 아이템을 빠르게 여러 번 선택하면,늦게 도착한 예전 요청의 응답이 가장 최근에 선택한 화면을 덮어쓴다.전형적인 Race Condition이다. Task.isCancelled로 막을 수 있을 거라 생각했는데, 처음 짠 코드는 체크 위치가 틀려서 막지 못했다. 이 글은 그 실수가 왜 실수였는지, cooperative cancellation의 동작 원리부터 짚어가며 정리한 글이다.구현하려는 상황다음과 같은 화면을 가정해보자.리스트에서 아이템을 선택할 때마다 상세 데이터(사진, 리뷰)를 비동기로 불러와 보여준다아이템을 다시 선택하면 이전 요청은 취소하고 새 요청을 시작해야 한다상세 데이터는 fetchPhoto, fetchReview..

iOS 2026.08.17 0

[SwiftUI] SwiftUI로 인스타 릴스 같은 스크롤 만들기

iOS 17+에서 추가된 scrollTargetLayout과 scrollTargetBehavior를 이해하고,릴스처럼 한 화면씩 스냅되는 피드를 만드는 방법을 정리한다.완성 코드 먼저ScrollView(.vertical) { LazyVStack(spacing: 0) { ForEach(posts) { post in PostView(post: post) .containerRelativeFrame([.horizontal, .vertical]) } } .scrollTargetLayout()}.scrollTargetBehavior(.paging).ignoresSafeArea()이 구조가 어떻게 동작하는지 하나씩 뜯어보자.스냅(..

SwiftUI 2026.04.24 0

Swift Actor로 Race Condition 해결하기 (feat. NSLock, DispatchQueue 비교)

WWDC21에 소개된 Actor 라는 개념이 있습니다.변경 가능한 상태를 보호하기 위해 Swift Actor를 도입했다고 합니다.변경 가능한 상태를 왜 보호해야할까?iOS는 멀티스레드 환경이므로 변경 가능한 상태에 대해두 스레드가 동시에 값을 쓰고자 할 경우Race Condition(경쟁 상태)가 발생할 수 있기 때문입니다.경쟁 상태는 하나의 값에 대해예제를 통해 알아볼게요.class Cart { var itemCount = 0}let cart = Cart()// 상품 추가DispatchQueue.global().async { cart.itemCount += 1}// 상품 삭제DispatchQueue.global().async { cart.itemCount -= 1}Thread.sleep..

iOS 2026.01.21 0

[iOS] UIPanGestureRecognizer 알아보기 (드로어 구조 만들기)

안녕하세요! 오늘은 UIPanGestureRecognizer에 대해 알아보도록 하겠습니다. PanGesture 먼저 PanGesture란, 애플 공식 문서에 나와있듯이 화면에서 한손가락 또는 두 손가락 이상으로 스크린위에서 움직일 때 나타납니다. 팬한다는 것은 쉽게 말하면 드래그 하는 것과 같아요. 그림을 보면 어떤 액션인지 더 이해가 가죠? 그래서 이런 panGesture는 손가락이 드래그 되면서 UIView와 같은 것을 이동시키거나, panGesture에 따라 어떤 액션을 정의하고 싶을 때! 사용합니다. UIPanGestureRecognizer는 UIGestureRecognizer를 상속 받고 이 외에 여러 gestureRecognizer 종류가 있으니 한번 살펴보세요. 👉UIGestureRecogn..

iOS 2021.03.07 2

[iOS] 아이폰에서 URL, 이메일 열기

안녕하세요! 오늘은 아이폰에서 URL을 여는 방법을 알아볼게요. 앱에서 아이폰 기본 메일앱으로 이동하거나 외부 링크로 연결되거나 하는 경우가 있는데요, 매우 간단한 방법으로 구현할 수 있습니다. 저는 이렇게 아래 코드와 같이 url을 스트링으로 받는 함수를 만들어서 사용했어요. 그냥 원하는 url을 넣어서 호출하시면 됩니닷! ㅎ.ㅎ 아래에 #available은 실행되는 기기의 iOS 버전에 따라 다르게 실행할 수 있도록 분기처리 해준 것입니다. func openURL(urlString: String){ if let url = URL(string: "\(urlString)"){ if #available(iOS 10.0, *){ UIApplication.shared.open(url) } else{ UIApp..

iOS 2021.02.28 0