글

라벨이 SwiftUI인 게시물 표시

iOS SwiftUI Factory with test

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.2 iOS 스위프트유아이 Factory with test를 알아보겠습니다. Factory는 DI(Dependency Injection, 의존성 주입)를 위한 라이브러리입니다. 그리고 Resolver라는 DI library를 대체하는 오픈 소스입니다. 공식 문서입니다. https://hmlongco.github.io/Factory/documentation/factory 참고 프로젝트: https://github.com/Jaehwa-Noh/Practice-Amphibians/tree/swiftui-factory-amphibians-app iOS SwiftUI Factory 게시글과 이어집니다. https://shwoghk14.blogspot.com/2024/01/ios-swiftui-factory.html Unit test부터 한 번 봅시다. import Factory를 해줍니다. AmphibiansViewModelTest.swift setUpWithError에 Container.shared.reset()을 해줍니다. 그리고 기존의 코드는 놔두고 그 밑에 Container.shared.networkAmphibiansInfoRepository.register를 적어줍니다. register는 우리가 이전 시간에 작성한 Container extension을 register에 적힌 함수로 대체하겠다는 뜻입니다. 즉, 가장 아래의 Container.shared.amphibiansViewModel()은 fakeAmphibiansInfoRepository가 사용되게 됩니다. 실행해 봅시다. 문제없이 잘 테스트가 됩니다. 다른 파일들도 이렇게 register를 사용해서 갈아주면 됩니다. NetworkAmphibiansRepositoryTest.swift AmphibiansRemoteDataSourceTest.swift UI test를 볼까요? 원래 앱의 Factory를 사용하기 때문에 따로 코드를 변경해 줄 필요가 없습니다...

iOS SwiftUI Factory

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.2 iOS 스위프트유아이 Factory를 알아보겠습니다. Factory는 DI(Dependency Injection, 의존성 주입)를 위한 라이브러리입니다. 그리고 Resolver라는 DI library를 대체하는 오픈 소스입니다. 아래는 Factory Github입니다. https://github.com/hmlongco/Factory 그리고 공식 문서입니다. https://hmlongco.github.io/Factory/documentation/factory 참고 프로젝트: https://github.com/Jaehwa-Noh/Practice-Amphibians/tree/swiftui-factory-amphibians-app 우선 설치부터 합시다. CocoaPods와 SPM(Swift Package Manager)를 모두 지원합니다. SPM을 사용해서 설치해 봅시다. File - Add Package Dependencies... Github 주소를 넣어주고 Add Package를 누릅니다. Add Package 클릭. 그러면 Xcode에 Factory Package가 보입니다. 설치가 다 되었네요. 여기 수동으로 Dependency Injection 한 것을 Factory를 사용하여 Injection 하는 걸로 변경해 봅시다. AppContainer.swift Data 그룹에 FactoryContainer 파일을 만듭니다. 기존에 있던 AppContainer와 App delegate들을 모두 삭제합니다. AppContainer.swift, AppDelegate.swift 삭제. Container에 extension을 만들어서 적어줍니다. 한 번 만들 때 가볍지 않고, 오랫동안 쓸 변수이기 때문에 singleton을 적어줍니다. userInitiated도 container에 추가합니다. 기본으로 만들면 unique를 사용하는 것으로 매번 새로운 Instance를 만듭니다. NetworkAmphibiansD...

iOS SwiftUI Asynchronous UI test

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.1 iOS 스위프트유아이 Asynchronous UI test를 알아보겠습니다. UI test는 Synchronization(동기식)으로 작동합니다. 그래서, 바로바로 테스트를 진행하죠. 하지만, 비동기 작업을 UI test(테스트)에서 확인할 때에는 문제가 발생합니다. 왜냐하면 test는 현재 작업 중인지 Idle(유휴) 상태인지 알 수 없기 때문에 바로 종료시키거든요. Swift에서는 해당 문제의 해결책으로 waitForExistence를 제공해 줍니다. https://developer.apple.com/documentation/xctest/xcuielement/2879412-waitforexistence 해당 XCUIElement가 존재하면 true를 반환하고, timeout(시간 초과)이 발동된다면 false가 반환됩니다. 사용법을 알아봅시다. 108 번째 줄처럼 waitForExistence를 사용해서 callButton이 다시 나타날 때까지 기다립니다. 테스트 화면입니다. Progressbar가 완료되어 Call이 다시 나타날 때까지 기다리는 것을 볼 수 있습니다. 참고 프로젝트: https://github.com/Jaehwa-Noh/Practice-Concurrency/tree/swiftui-castle-app 끝. 카테고리: iOS, SwiftUI

iOS SwiftUI Asynchronous unit test with timeout

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.1 iOS 스위프트유아이 Asynchronous unit test with timeout을 알아보겠습니다. Concurrency(동시성)을 이용하여 만든 함수를 Unit(유닛) test 하려면 어떻게 해야 할까요? 또, 일정 시간 지난 뒤에 값을 확인하고 싶다면 어떻게 해야 할까요? 위의 두 문제를 해결하기 위해 Task, async, await 등의 키워드를 사용하여 테스트하는 방법을 알아봅니다. 요런 async(어씽크) 함수가 있습니다. 이 함수를 테스트하려면 이렇게 합니다. Test Case 함수에 async를 붙여줍니다. 또, try를 사용하게 된다면 throws도 같이 적어줍니다. 그리고 테스트할 함수에는 await를 적어줍니다. 위와 같이 테스트를 작성하면 해당 함수가 완전히 완료되는 경우가 확인 가능합니다. 만약 중간에 멈추고 값을 확인하고 싶다면 어떻게 해야 할까요? 예를 들어 1초마다 5를 더하는 함수가 있다면, 5초 때에는 25인지 확인하고 싶다면 위의 방법으로는 확인할 수 없습니다. 이럴 때 사용하는 것이 withThrowingTaskGroup입니다. group.addTask를 활용해서 Task Group에 Task를 추가합니다. 42번째 줄처럼 하나의 Task(테스크)는 Task.sleep을 이용해서 멈추는 시간을 지정합니다. 44번째 줄처럼 group.next를 사용하면 child task 중에 가장 먼저 반환되는 값을 기다립니다. 둘 중 하나가 종료되면 group.cancelAll로 모든 작업을 종료합니다. 그러면, 중간에 작업이 중단되기 때문에 중간 값을 확인할 수 있습니다. 참고 프로젝트: https://github.com/Jaehwa-Noh/Practice-Concurrency/tree/swiftui-castle-app 끝. 카테고리: iOS, SwiftUI

iOS SwiftUI onTapGesture works at the wrong position

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.0.1 iOS 스위프트유아이 onTapGesture works at the wrong position을 알아보겠습니다. 이상한 위치에서 onTapGesture가 실행될 때에는 어떻게 해야 할까요? 알아봅시다. onTapGesture는 해당 뷰를 눌렀을 때 실행되는 콜백입니다. 그래서 제가 어떤 뷰를 눌렀을 때 작동되는 것을 예상하고 사용했습니다. 그런데 웬걸 위에 걸 눌렀는데, 밑에 있는 뷰가 눌려지는 겁니다. 한 번 보시죠. 너무 황당하지 않나요? 사용된 코드입니다. 해결 방법은 다음과 같습니다. 현재, 뷰의 영역이 보이는 것과 다르게 엉망으로 생성되나 봅니다. 그렇다면 영역을 제대로 지정해 주면 해결되겠죠? .contentShape를 추가로 적어줍니다. 실행해 볼까요? 참고 프로젝트 https://github.com/Jaehwa-Noh/Project-30-Days-App/tree/SwiftUI-30-Days-App 끝. 카테고리: iOS, SwiftUI

iOS SwiftUI Custom fonts

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.0.1 iOS 스위프트유아이 Custom fonts를 알아보겠습니다. 앱의 목적에 따라서 다양한 Font(글꼴)를 사용해야 할 때가 있습니다. 오늘은 SwiftUI에서 Font를 사용하는 방법을 알아봅니다. 공식 문서입니다. https://developer.apple.com/documentation/swiftui/applying-custom-fonts-to-text/ Xcode에 Group을 하나 만듭니다. 프로젝트 그룹 - 우클릭 - New Group Project Fonts라고 이름을 지어줍니다. 사용할 Font를 방금 만든 그룹으로 옮겨줍니다. '.ttf' 확장자입니다. Add to targets에 Font를 사용할 프로젝트를 선택해 줍니다. 폰트가 추가되었습니다. 프로젝트 - Info로 갑니다. Key에 Fonts provided by application을 입력하고 하위에 우리가 추가한 Font ttf 파일을 적어줍니다. 사용법은 다음과 같습니다. .font(Font.custom(name, size, relativeTo) relativeTo를 적지 않으면 body와 연결되고, 아래처럼 .largeTitle로 지정할 수 있습니다. 짜잔. 실행 결과입니다. https://github.com/Jaehwa-Noh/Practice-Superheroes-app/tree/swiftui-superheroes 끝. 카테고리: iOS, SwiftUI

iOS SwiftUI Unit test

이미지
사용 언어: Swift 5 사용 버전: Xcode 15.0.1 iOS SwiftUI Unit test를 알아보겠습니다. Unit test(유닛 테스트, 단위 테스트)는 작성한 함수의 기능이 올바르게 작동하는지 확인하기 위해 사용합니다. 일일이 앱을 실행하여 확인하기보다는 자동으로 확인하기 때문에 유지 보수 시간을 줄일 수 있습니다. UI test도 있지만, 여기선 다루지 않겠습니다. 현재 파일 트리입니다. 이번에 테스트할 updateCurrentPage 함수입니다. Page를 업데이트하는 기능을 합니다. 테스트할 함수도 있으니 테스트 파일을 만듭시다. 프로젝트 - '+' 버튼을 눌러줍니다. test를 검색하고, Unit Testing Bundle을 선택합니다. 여기서 다루지는 않지만, UI Testing을 하고 싶다면 UI Testing Bundle을 선택하면 됩니다. 적당한 이름을 적고 Finish를 누릅니다. 이렇게 파일이 생성됩니다. 9번째 줄처럼 @testable import로 테스트할 함수가 있는 모듈을 불러옵니다. 13번째 줄처럼 테스트할 객체를 정의합니다. 15번째 줄의 setUpWithError()는 테스트가 실행되기 전에 먼저 실행되는 부분으로 객체를 할당합니다. 20번째 줄의 tearDownWithError()는 테스트가 종료되면 실행되는 부분으로 객체를 해제합니다. 테스트할 코드로 갑니다. private를 internal로 변경하여 테스트 코드가 접근할 수 있게 만들어 줍니다. 이제, 테스트할 함수를 작성합니다. 함수의 이름은 test로 시작해야 합니다. 31번째 줄의 XCTAssertEqual는 currentPage 값이 0이라고 확신하는 걸 의미합니다. 즉, 0이 아니면 확신이 틀리기 때문에 오류가 나올 것이고, 0이 맞는다면 확신이 맞기 때문에 무사히 넘어갑니다. class 옆에 재생을 누르면 테스트가 실행됩니다. 테스트를 모두 통과하면 이렇게 passed가 나옵니다. 한 번 틀린 걸 넣어볼게요. 이렇게 바로 오류가 나옵...