iOS 62

Swift Testing 테스트 코드 작성하기

오늘은 Swift Testing을 사용해, TCA로 작성된 코드의 비즈니스 로직을 테스트한 과정을 작성해보겠습니다. TestStore 사용법, 의존성 주입을 통한 네트워크 제어 등을 제가 작성한 코드를 보면서 설명해보겠습니다.예제는 영화 목록 화면의 로직입니다.테스트 목표 .onAppear 액션이 데이터 요청 로직을 정확히 트리거하는지세 가지 다른 API(Now Playing, Upcoming, Popular)가 각각 잘 호출되는지각 API 응답이 올바른 상태(State)를 갱신하는지1. Swift Testing 개념Swift Testing은 기존 XCTest 대비 문법이 간결합니다.@Test("테스트 설명")으로 케이스 선언#expect(조건)으로 결과가 예상과 일치하는지 확인async/await 지원..

iOS

@ObservableState와 @BindingState 충돌 트러블 슈팅

안녕하세요! 오늘은 SwiftUI와 TCA(The Composable Architecture)로 영화 검색 기능을 구현하던 중 만났던 컴파일 에러와 해결 과정을 공유해 보려고 합니다. 문제 발생영화 검색을 위한 MovieSearchFeature를 만들고 있었습니다. 검색어를 입력받을 searchText 상태를 만들고, SwiftUI View에서 양방향으로 데이터를 주고받기 위해 TCA에서 제공하는 @BindingState를 사용했습니다. @Reducerstruct MovieSearchFeature { @ObservableState struct State: Equatable { // ... @BindingState var searchText: String = "" } enum Ac..

iOS

Swift 6에 새로 등장한 InlineArray

몇주 전에 포스팅에서 Swift의 Array가 어떻게 동적으로 크기를 조절하며, 그 과정에서 발생하는 메모리 재할당과 성능 비용에 대해 알아봤었습니다. Array의 편리함 이면에는 힙(Heap) 메모리 할당과 복사라는 숨은 비용이 있다는 점을 기억하실 겁니다.그 숨겨진 비용을 줄여줄 수 있는 또다른 방법인 InlineArray에 대해 이야기해보려 합니다!InlineArray가 뭔가요?InlineArray는 이름 그대로, 데이터를 인라인(inline)으로 저장하는, 컴파일 시간에 크기가 고정된 배열입니다.가장 큰 특징은 기존 Array처럼 데이터를 힙 메모리에 별도로 할당하는 것이 아니라, InlineArray를 감싸고 있는 타입의 메모리 공간 안에 직접 값을 저장한다는 점입니다. 만약 함수 내의 지역 변..

iOS

Alamofire, Sendable 에러 트러블 슈팅

안녕하세요 오늘은 Alamofire를 함께 사용하면서 겪은 Main actor-isolated conformance... 에러를 해결해 나간 과정을 공유해 보려고 합니다. 1. 에러 발생 및 첫 시도Alamofire를 통해 데이터 통신을 시도하던 중 에러가 발생했습니다.func fetchExchangeRates(completion: @escaping (Result) -> Void) { // Alamofire로 GET 요청 AF.request(url, method: .get) .validate() // 상태 코드 200~299가 아니면 실패 처리 .responseDecodable(of: ExchangeRateResponse.self) { response in switch respon..

iOS

Array의 메모리 재할당과 reserveCapacity(_:)

안녕하세요. 최근에 코딩 테스트 문제를 풀다가 시간초과 때문에 헤맨 경험이 있습니다. 분명 알고리즘의 시간 복잡도는 문제의 제한 사항을 충분히 만족한 것 같은데 계속해서 시간 초과가 뜨는 상황이었죠. 문제는 너비 우선 탐색(BFS)을 사용하는 그래프 문제였고, 수만 개의 노드를 큐에 넣고 빼는 로직이었습니다."내 BFS 로직이 잘못됐나? 포인터 관리가 비효율적인가?" 등등 고민을 하다가 해결방법을 찾아냈습니다. 원인은 알고리즘이 아니라, 너무나도 당연하게 사용하던 Array의 append 때문이였습니다. 그리고 그 해결책은 reserveCapacity라는 메서드 였습니다.Swift 배열의 메모리 재할당우리는 보통 Swift에서 가변 크기의 배열이 필요할 때 아무 생각 없이 빈 배열을 선언하고 append..

iOS

배열을 순회하며 수정할 때 for-in으로 배열을 직접 순회하면 안되는 이유

안녕하세요. 오늘은 알고리즘 코딩 테스트 문제를 풀면서 겪은 문제상황과 그 이유를 알아보는 과정에서 알게된 내용을 이야기해보려고합니다. DFS 문제를 풀고 예제 케이스를 돌려보는데 예상과 다르게 계속 실패가 떠서 원인을 찾기 위해 print를 찍어보며 디버깅을 했습니다. 분명히 visited[1] = true로 값을 바꿨는데 바로 다음 반복문에서 visited의 1번 인덱스가 여전히 false로 읽히는 것을 보았습니다.문제의 코드는 그래프의 모든 노드를 방문했는지 확인하고 방문 여부에 따라 함수를 실행하는 코드였습니다.var visited = Array(repeating: false, count: n)func dfs(computer: Int) { visited[computer] = true for (..

iOS

Core Data 사용해보기

안녕하세요! 오늘은 앱 내부에 데이터를 저장해야 할 때 체계적으로 데이터 관리를 할 수 있는 Core Data를 사용해본 경험을 공유해보겠습니다. 시작하기 전에: CRUD란?개발을 하다 보면 CRUD라는 용어를 정말 자주 듣게 되죠. 데이터베이스의 기본 개념으로, 각각 다음을 의미합니다.Create: 데이터 생성Read: 데이터 읽기Update: 데이터 수정Delete: 데이터 삭제간단히 '전화번호부 앱'을 예로 들면, 새로운 연락처를 추가(Create)하고, 저장된 연락처를 조회(Read)하며, 번호나 이름을 수정(Update)하고, 필요 없는 연락처를 삭제(Delete)하는 모든 과정이 바로 CRUD입니다.이번 글에서는 Apple의 프레임워크인 Core Data를 사용해서 기기 내부에 데이터를 저장하..

iOS

그래프 탐색 BFS와 DFS

오늘은 그래프를 탐색하는 대표적인 두 가지 방법, BFS(너비 우선 탐색)와 DFS(깊이 우선 탐색)를 Swift 코드로 함께 살펴보겠습니다. DFS는 재귀와 스택 두 가지 방식으로 구현했는데 어떤 상황에 어떤 방식을 쓰는 게 유리한지 장단점까지 이야기해보도록 하겠습니다!BFS (너비 우선 탐색)BFS는 이름 그대로 넓게 탐색하는 방식입니다. 시작점에서 가장 가까운 노드들부터 방문하고 그다음 가까운 노드들 순서로 퍼져나가듯 탐색을 진행합니다.BFS의 핵심은 "먼저 찾은 노드를 먼저 탐색한다"는 것이고, 이걸 가능하게 해주는 자료구조가 바로 큐(Queue)입니다. 선입선출(FIFO) 구조인 큐 덕분에 탐색 순서가 보장되죠.그래서 BFS는 주로 두 노드 사이의 최단 경로를 찾거나, 연결된 모든 노드를 순회할..

iOS

TCA 사용해서 장바구니 동작 완성하기

어제는 Cart 버튼을 누르면 CartView가 시트로 열리도록 TCA 흐름을 정리했습니다. 오늘은 그 시트에 데이터를 넣고 사용자가 원하는 대로 장바구니를 조작할 수 있게 만드는 과정을 기록해 보겠습니다. 버튼에서 넘겨준 선택 상품을 장바구니에서 확인하고 수량 증감/단품 삭제/전체 비우기/결제 완료 알림까지 연결하는 것이 목표입니다.1. CartFeature로 상태 넘기기1) @Shared로 ProductList와 Cart 상태 공유선택된 상품을 담은 selectedProducts는 이미 @Shared로 선언되어 있어서 Cart 시트에서도 같은 selectedProducts배열을 바라볼 수 있었다. CartFeature의 state에 selectedProducts 값을 그대로 주입하면, 변경된 항목이 ..

iOS

TCA 사용해서 버튼으로 시트 띄우기

새로운 프로젝트를 TCA(Composable Architecture)로 진행하면서 장바구니 버튼을 누르면 장바구니 화면을 시트로 띄우는 요구사항을 만나게 되었다. SwiftUI만 쓸 때는 @State랑 sheet(isPresented:) 정도면 끝났는데, TCA를 처음 쓰다 보니 상태는 어디에 두고, 액션은 어떻게 전달하고, 시트는 또 어떻게 열어야 하는지 막막했다. 이 글은 Cart 버튼 → CartView를 시트로 띄우기 흐름을 만들기까지의 시행착오와 해결 과정을 적어둔 기록이다.일단 시트로 열리는 것은 확인했는데 당연히 구조적으로 개선해야할 부분은 있을거라고 생각해서 이 글을 작성해두고 나중에 다시 보고 수정을 하면서 어떻게 생각했었는지, 어떤 부분을 바꾸면 좋을지 고민해볼 수 있을 것 같다. (..

iOS