iOS 14

[iOS] RxSwift + Swift Testing

✅ 왜 RxBlocking이 필요할까? RxSwift는 비동기 스트림을 다루는 라이브러리입니다. 하지만 테스트는 동기적으로 결과를 확인해야 합니다// ❌ 이렇게 하면 안 됨 - 비동기라서 테스트가 끝나기 전에 완료됨func test_잘못된_방법() { let result = userRepository.getUser(id: 1) // Single // result는 아직 실행되지 않은 스트림일 뿐! #expect(result == expectedUser) // 컴파일 에러!}// ✅ RxBlocking으로 동기화func test_올바른_방법() throws { let result = try userRepository.getUser(id: 1) .toBlocking() ..

iOS 2025.07.31

[iOS] Factory Pattern

Factory Pattern이 필요한 이유만약 처음에 단순하게 버튼을 이렇게 만들었다// 처음엔 이렇게 만들었지...let button = UIButton()button.setTitle("확인", for: .normal)button.backgroundColor = .blue 그런데 기획자가 와서 말합니다: "아, 이제 라이트 모드랑 다크 모드 두 가지로 만들어주세요!" // 이제 이런 코드가 앱 곳곳에...if isDarkMode { let button = UIButton() button.setTitle("확인", for: .normal) button.backgroundColor = .black button.setTitleColor(.white, for: .normal)} else ..

iOS 2025.07.24

[iOS] Coordinator 패턴 적용기

📚 Coordinator 패턴이란?네비게이션 로직을 View Controller에서 분리하여 별도의 객체가 담당하도록 하는 아키텍처 패턴기존 방식의 문제점View Controller가 다른 View Controller를 직접 생성하고 present/push네비게이션 로직이 여러 곳에 분산되어 관리가 어려움View Controller 간의 강한 결합 Coordinator 패턴의 개념들1. childCoordinators 배열의 역할var childCoordinators = [Coordinator]() // 메모리 관리를 위한 배열메모리 관리를 위한 것배열에 추가 = 메모리에서 해제되지 않게 유지배열에서 제거 = 메모리에서 해제2. coordinator = self를 하는 이유let homeVC = Hom..

iOS 2025.07.22

[트러블슈팅] UICollectionViewCell 그림자가 초기 렌더링 시 안 보이는 문제

🚨문제상황셀 내부이미지에 shadow를 적용했지만 최초 실행 시 보이지 않음스크롤 후 다시 돌아오면 그림자가 정상적으로 보임아래 사진 순서 대로 1,2번은 안보이고 스크롤 하면 3번부터 보임, 다시 돌아오면 2,1 순으로 그림자가 생김 🔎 문제 원인AutoLayout이 완전히 적용되기 전에 shadowPath 설정containerView.bounds가 아직 계산되지 않은 상태여서 (0,0,0,0)이 찍힘override func layoutSubviews() { super.layoutSubviews() containerView.layer.shadowPath = UIBezierPath( roundedRect: containerView.bounds, // ❌ 초기에 bounds가..

iOS 2025.07.18

[iOS] Coordinator 패턴으로 화면 전환 로직 분리하기

기존의 ViewController에서 직접 화면 전환을 처리하는 방식이 마음에 들지 않아 Coordinator 패턴을 적용해보았다. ✅ Coordinator 패턴화면 전환(네비게이션) 로직을 별도의 객체로 분리하는 디자인 패턴 기존 문제점// ViewController가 다른 ViewController를 직접 알고 있어야 함class ExchangeRateViewController: UIViewController { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let calculatorVC = CalculatorViewController(exchangeRate: rate) na..

iOS 2025.07.10

[iOS] 클로저에서 async/await로 리팩토링하기

기존에 배웠던 클로저 기반 네트워킹에서 async/await 방식으로 리팩토링 아닌 리팩토링을 해보았다 ✅ 기존 방식 (클로저 기반)private func fetchData() { session.dataTask(with: request) { (data, response, error) in guard let data, error == nil else { return } if let response = response as? HTTPURLResponse { if (200.. ✅ async/awaitfunc fetchData(url: URL) async -> Result { do { let (data, response) = tr..

iOS 2025.07.08

[iOS] 성능 최적화: @inlinable과 lazy

✅ @inlinable이란?@inlinable은 컴파일러에게 특정 함수나 계산 속성을 인라인 최적화할 수 있다고 알려주는 키워드인라인 최적화: 함수 호출 대신 함수의 실제 코드를 호출 지점에 직접 삽입하는 것// 일반적인 함수 호출func square(_ x: Int) -> Int { return x * x}let result = square(5) // 함수 호출 오버헤드 발생// @inlinable로 최적화된 경우@inlinablefunc square(_ x: Int) -> Int { return x * x}let result = 5 * 5 // 컴파일러가 직접 코드 삽입 ✅ @inlinable의 특징성능 향상: 함수 호출 오버헤드 제거모듈 경계 최적화: 다른 모듈에서도 인라인 최적화 가능..

iOS 2025.06.25

[iOS] Unit Test 기본 개념과 적용

✅ 단위 테스트(Unit Test)란?정의: 코드의 작은 단위(예: 함수, 메서드)가 예상대로 동작하는지 자동으로 확인하는 것// 예를 들어, 이런 함수가 있다면func add(a: Int, b: Int) -> Int { return a + b}// 테스트는 이런 식으로 검증// "add(2, 3)을 호출하면 5가 나와야 한다" ✅ 테스트의 핵심 개념1. Given-When-Then 패턴모든 테스트는 이 3단계로 구성func test_saveSummaryState_shouldSaveCorrectly() { // Given (준비): 테스트에 필요한 데이터 준비 let bookTitle = "Harry Potter" let isExpanded = true // When ..

iOS 2025.06.23

[iOS] MVVM 패턴에서 데이터 로딩 책임 분리

✅ 문제 상황json 파일에 있는 데이터를 파싱해와서 보여주는 과제를 하던 중 ViewController의 viewDidLoad()에서 데이터 로딩 로직을 처리하고 있는 것이 MVVM 패턴에 적합하지 않다고 느꼈다.기존 코드 (문제가 있던 코드)// BookViewController.swiftoverride func viewDidLoad() { super.viewDidLoad() setupViews() setupConstraints() // 🚨 문제: ViewController에서 데이터 로딩 제어 viewModel.loadBooks { [weak self] result in switch result { case .success: ..

iOS 2025.06.18

[아키텍처] Clean Architecture + MVVM

1. Clean Architecture 기본 개념3개 레이어: Presentation (UI 로직) → Domain (비즈니스 로직) ← Data (데이터 접근)의존성 규칙: 내부 레이어는 외부 레이어에 의존하지 않음핵심: 비즈니스 로직을 UI/DB로부터 완전히 독립시키는 것2. Domain Layer 상세 분석// Domain Layer 구성📁 Entities (비즈니스 모델) - Movie.swift - MovieQuery.swift📁 UseCases (비즈니스 로직) - SearchMoviesUseCase.swift - FetchRecentMovieQueriesUseCase.swift📁 Interfaces/Repositories (의존성 역전) - MoviesRepository.s..

iOS 2025.06.13