안녕하세요. 이번에는 RxSwift를 통한 MVVM 구현 과정에서 사용하면 좋은 Input Output 패턴에 대해 포스팅하겠습니다. Input Output 패턴을 사용하지 않아도 MVVM 구현이 안 되는 것은 아니지만 사용해본 결과 뷰에서 발생하는 이벤트는 Input 구조체에서, 뷰모델에서 비즈니스 로직을 통해 처리하고 가공한 데이터를 전달받는 부분은 Output 구조체에 작성되어 있어 굳이 코드를 다 읽어보지 않아도 한눈에 흐름을 알 수 있고, 협업할 때에도 다른 사람이 작성한 화면의 기능을 파악하기 쉽다는 장점이 있습니다. 간단한 기능을 통해 Input Output 패턴을 이용하여 MVVM을 작성해 보겠습니다. 아래는 github 사용자리스트 api를 이용해 사용자 목록을 받아와서 테이블에 보여주는..
안녕하세요. 이번에 동영상 스트리밍 관련 앱 (like 틱톡, 릴스, 인스타 스토리)을 만들다가 정보가 너무 없거나 잘못된 게 많아서 직접 개발하며 알게 된 것들을 소개해보려고 합니다. 음 먼저 HLS라는건 동영상 스트리밍을 위한 Http Live Streaming의 약자로, 이름에서 알 수 있듯이 범용적인 http를 통해 비디오를 전송하는 비디오 스트리밍 프로토콜입니다. 애플에서 개발했지만 안드로이드나 타 서비스에서도 사용 가능합니다. 숏폼 동영상 플랫폼을 개발하기로 했는데, 숏폼 동영상이라는 특성상 연속적으로 기다림 없이 빠르게 재생을 해야 될 필요가 있었고 HLS는 네트워크 상황에 따라 스트리밍 중 비디오 품질을 조정하는 기능이 있어서 네트워크 상황이 나빠도 끊김 없이 연속적인 재생이 가능했기 때문..
안녕하세요. 이전에 [iOS] Authenticator 프로토콜로 JWT 인증 구현하기 라는 JWT 인증 관련 글을 올린 적이 있는데 그때는 무슨 일인지 adapt와 retry가 호출되지 않아서 Authenticator를 사용 했었는데요. 이번에 다시 해보니 잘 호출되고 오히려 Authenticator 보다 쉽고 간편한 부분이 있어 RequestInterceptor 프로토콜에 대해 포스팅하려고 합니다. JWT 인증 JWT 인증에 대해 앱 개발 관점에서 간단히 짚고 넘어가자면, 우리가 api 요청을 할 때 서버에서 인증된 사용자의 요청인지 판단하는 인증 방식으로 보통 로그인할때 accessToken과 refreshToken을 내려받습니다. 각각은 토큰의 유효기간이 있고 accessToken은 일반적인 요청..
안녕하세요. 컬렉션 뷰 써보려고 토이 프로젝트하다가 이미지 캐싱을 구현하게 돼서 블로그에 정리해 보려고 합니다. 원래 이미지 캐싱은 kingFisher를 많이들 사용하시던데 토이프로젝트 수준에서는 복잡한 로직이 없기 때문에 직접 구현해 보았는데요. 바로 이 NSCache를 통해 이미지 캐싱을 간편하게 구현할 수 있었습니다. NSCache는 Key-Value 형태의 데이터를 임시적으로 저장하는데 사용하는 가변 컬렉션이라고 되어있네요. 캐싱에는 보통 디스크에 저장하는 방법과 메모리에 저장하는 방법이 있는데 NSCache는 메모리에 저장하는 방식이며 kingFisher도 메모리 캐싱할 때는 내부적으로 NSCache를 사용합니다. 메모리에 캐싱하면 메모리 용량이 부족하거나, 앱을 종료했을때 데이터가 삭제됩니다...
JWT 샘플 앱을 MVC 패턴으로 만들었는데, rxSwift 없이 MVVM을 적용하면서 배운 것들을 블로그에 정리해보려 합니다. Apple's MVC 좌측이 Classic MVC 우측이 apple's MVC인데, iOS 앱 개발 관점에서는 ViewController가 View의 LifeCycle과 깊게 연관되어 있어 View와 Controller의 책임을 나누기가 어렵습니다. 그래서 우측과 같은 애플만의 MVC 패턴이 나오게 되었는데 이 경우 ViewController의 사이즈가 너무 커져서 재사용성이 떨어지고 테스트 관점에서 볼 때도 모델이야 따로 떨어져 있으니 테스트가 된다고 쳐도 View와 Controller를 각각 따로 테스트하기가 어려워집니다. 익숙한 패턴이라 개발 속도도 빠르고 새로운 개발자가..
샘플 프로젝트에 MVVM 적용하면서 ViewModel을 통해 비동기로 API 호출하는 로직을 unitTest 할 일이 있었는데, 처음에 이런식으로 api 호출 후에 성공하면 completionHandler 에서 isSuccess를 true로 바꿔주고 XCTAssertTrue에서 isSuccess가 true면 테스트가 성공하게 짰더니 completionHandler가 실행되기 전에 testLogin 메서드가 종료되어 버려서 테스트에 실패하더라구요. 찾아보니 애플 Developer 사이트에 위와같은 예제가 있던데 expectation을 이용해 지정한 시간만큼 대기하다가 시간안에 fulfill이 되면 다음 작업을 실행하고 fulfill이 되지 않으면 timeout되어 test 메서드가 실패한다고 되어있네요. ..
안녕하세요. 리더가 JWT 인증 관련 샘플 앱을 만들어보라고 해서 만드는 김에 블로그에 정리하려고 합니다. 처음에는 아래의 프로토콜에 포함된 adapt와 retry 메서드를 이용해 jwt 인증을 구현하려고 했습니다. protocol RequestInterceptor : RequestAdapter, RequestRetrier func adapt(_ urlRequest: URLRequest, for session: Alamofire.Session, completion: @escaping (Result) -> Void) func retry(_ request: Request, for session: Alamofire.Session, dueTo error: Error, completion: @escaping (R..
iOS 아키텍처 패턴, 디자인 패턴에 대해 알아보던 중 VIPER 패턴에 대해 공부할 일이 있어서 겸사겸사 블로그에 정리해보려고 합니다. Apple's MVC 좌측이 Classic MVC 우측이 apple's MVC인데, iOS 앱 개발 관점에서는 ViewController가 View의 LifeCycle과 깊게 연관되어 있어 View와 Controller의 책임을 나누기가 어렵습니다. 그래서 우측과 같은 애플만의 MVC 패턴이 나오게 되었는데 이 경우 ViewController의 사이즈가 너무 커져서 재사용성이 떨어지고 테스트 관점에서 볼 때도 모델이야 따로 떨어져 있으니 테스트가 된다고 쳐도 View와 Controller를 각각 따로 테스트하기가 어려워집니다. 익숙한 패턴이라 개발 속도도 빠르고 새로운..
안녕하세요. 오늘은 iOS 개발에 가장 필수적인 parsing과 관련된 ObjectMapper와 codable에 대해 정리해 보려고 합니다. 일단 임의의 JSON String을 만들고 ObjectMapper와 codable을 이용해서 각 Model을 만든 후 parsing 해보겠습니다. let jsonString = """ { "msg": "success", "data": { "token": "skfkajopdjvosvjopcvjs", "name": "gwan", "age": 28 } } """ ObjectMapper 임의로 JSON String을 생성했고, json 형태를 보고 Mappable 프로토콜을 채택한 Model을 만들었습니다. struct Profile: Mappable { var msg: ..
- Total
- Today
- Yesterday
- @propertyWrapper
- swift cache
- UserDefault
- ios 캐시메모리
- inputoutput패턴
- UserDefaults
- ios 이미지캐싱
- ios image caching
- ios 유닛테스트
- ios 캐시
- ios memory
- MVVM패턴
- UserDefaultKey
- wrappedValue
- SWIFT
- swift 캐싱
- ios 패턴
- 비동기 유닛테스트
- ios expectation
- 프로퍼티래퍼
- 연산프로퍼티
- rxswift 없이
- 앱개발 디자인패턴
- rxswift안쓰고
- ios cache
- NSCache
- 아키텍처패턴
- api호출 unittest
- swift mvvm
- ios 디자인패턴
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |