iOS 13

[SwiftUI] MVVM 패턴 간단한 예제 + 다형성

서론MVVM의 핵심은 뷰와 비즈니스 로직을 분리하는 것입니다.SwiftUI에서 뷰와 비즈니스 로직을 엮어버리면 다음과 같은 그림이 됩니다.struct ContentView: View { @State private var count = 1 var body: some View { VStack { Text("count : \(count)") .onTapGesture { /* 비즈니스 로직 */ count += 1 } } }} 이런 코드는 다음과 같은 문제가 있습니다.1. 테스트의 어려움비즈니스 로직"만"을 테스트하..

iOS/SwiftUI 2024.11.14

Delegate Pattern을 왜 썼을까?

이렇게 생긴 버튼들의 집합을 구현하기 위해 ButtonsView라는 클래스를 만들었습니다.그리고 ViewContoller와 Delegate를 통해 데이터를 주고받도록 했습니다.사실 ButtonsView 클래스에서 onTapLike() 와 같은 함수를 두어서 buttonsView.onTapLike() 이런식으로 직접 조작을 할 수도 있었을 것입니다.하지만, 왜 Delegate Pattern을 "굳이" 썼는지 정리해보고자 합니다. 1. 구조VC는 Delegate를 구현하는 방식으로 의존하고, ButtonsView는 Delegate를 선언하고 사용하는 방식으로 의존합니다.ButtonsView 입장에서는 함수들을 "직접 구현"하는 것이 아니라, "위임"하게 됩니다. 그래서 명칭이 Delegate Pattern입..

iOS/UIKit 2024.09.03

[UIKit/Refactoring] 전시 화면 데이터 처리 관련 로직 개선하기

- OverviewPLAIN 앱의 전시화면은 이렇게 생겼습니다. (데이터는 가짜입니다.) * mock data ref더보기https://www.google.com/url?sa=i&url=https%3A%2F%2Ftwitter.com%2FChampionsLeague%2Fstatus%2F1348932678297538561&psig=AOvVaw0c_KgXbB1BnBijOhuVlyaS&ust=1722327969680000&source=images&cd=vfe&opi=89978449&ved=0CBEQjRxqFwoTCIDCmejpy4cDFQAAAAAdAAAAABAEhttps://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.pinterest.com%2Fpin%2Flionel-me..

iOS/Refactoring 2024.08.17

[UIKit/Refactoring] Domain + Presentation + MVVM 아키텍처 개선

기존 아키텍처 및 개선의 필요성domain layer + presentation layer + mvvm 파란색 선: 의존기존 아키텍처는 이런 모습으로 구현되어 있었습니다. 의존성이 내부로 향하는 것이 클린 아키텍처의 핵심이라 하면, 문제는 없었습니다.다만, 개발을 빠르게 하다보니 이것이 지켜지지 않는 문제들이 있었습니다.뷰컨에 모델이 들어간다던지, 네비게이션을 직접 한다던지 등등 SRP를 어기는 코드가 있었습니다.또한, 뷰모델에 많은 로직이 들어가 있었는데 뷰와 관련된 로직이 포함된 뷰모델을 테스트하기 어려운 문제도 있었습니다.따라서, 코드를 리팩토링하고 data layer를 추가해서 테스트 가능한 영역을 구분하기로 결정했습니다.  개선된 아키텍처 개선된 구조의 모습입니다.데이터 흐름은 presentat..

iOS/Refactoring 2024.08.09

WWDC24 - Meet Swift Testing

https://developer.apple.com/videos/play/wwdc2024/10179/ Meet Swift Testing - WWDC24 - Videos - Apple DeveloperIntroducing Swift Testing: a new package for testing your code using Swift. Explore the building blocks of its powerful new API, discover...developer.apple.com * XCode16 부터 지원되는 기능입니다.  Building blocks 파일을 추가할 때 새로 생긴 템플릿이 생긴걸 볼 수 있습니다.  @Test attribute함수가 테스트라는 것을 나타냅니다. 이걸 붙이면 XCode가 테..

iOS/WWDC 2024.08.03

[UIKit/Refactoring] 홈 화면 UX 개선하기 (리사이징, 메모리 캐싱)

- 문제 상황홈 화면에서 스크롤 시, 앱이 버벅인다는(렉이 걸린다는) 이슈를 제보받았습니다.실제로 구동을 해보니, 앱이 버벅이고 있었고 메모리 사용량도 심상치 않았습니다.이 문제는 저도 알고 있는 문제였습니다. 하지만, 매번 시뮬에서 테스트하다보니 "시뮬이라서" 렉이 걸리는구나라고 생각하고 있었습니다.  앱의 홈 화면은 이렇게 생겼습니다. - 메모리 디버그순환참조로 인한 메모리 누수 등 메모리로 인한 문제가 아닐까 생각해 메모리 디버그를 확인했습니다. * 아래 문제 상황 설명은 iPhoneXS 디바이스 기준입니다. 앱을 처음 진입한 이후의 메모리 사용입니다.   스크롤을 딱 한번 했을 때의 메모리 사용입니다.이미지 하나의 크기가 5~10MB인걸 감안했을 때, 뭔가.. 뭔가 비정상적이라고 느꼈습니다.  위..

iOS/Refactoring 2024.07.27

[UIKit/Refactoring] MyPageProfileEditViewModel 코드 개선하기 (2)

이전글 : https://ios-dev-su.tistory.com/13 MyPageProfileEditViewModel 코드 개선하기 (1)기존 코드 수정 전의 기존 코드는 다음과 같습니다.더보기 import UIKitimport Combineimport Alamofireimport Kingfisherfinal class MyPageProfileEditViewModel { // MARK: - Properties private let coordinator: MyPageCoordinator private varios-dev-su.tistory.com 이번 포스팅에서는 코드와 구조도 개선하도록 하겠습니다. - tagFieldChangedFromUser() 함수 개선// 유저의 텍스트필드 입력에 따른 뷰모델 및..

iOS/Refactoring 2024.07.17

[UIKit/Refactoring] MyPageProfileEditViewModel 코드 개선하기 (1)

기존 코드 수정 전의 기존 코드는 다음과 같습니다.더보기 import UIKitimport Combineimport Alamofireimport Kingfisherfinal class MyPageProfileEditViewModel { // MARK: - Properties private let coordinator: MyPageCoordinator private var interactor = MyPageDownloadInteractor() @Published var categoryTagItemSelectCount: Int = 0 var categoryTagItems = [TagItem(tag: "제품 디자이너", isSelected: false), TagItem..

iOS/Refactoring 2024.07.13

[UIKit/Refactoring] MyPageNotificationViewModel 코드 개선하기

1 저는 이런식으로 주석을 달아서, 어느 파트가 눈에 쉽게 보이는지를 구성해왔습니다.근데, 주석은.. 기껏해야 주절주절이기 때문에, 삭제하기로 했습니다.또한, extension으로 구분하는 것도 없앴습니다. 2func readNotification(index: Int) { if notifications[index].status == .UnRead { notifications[index].status = .Read putNotificationReadStatus(notificationId: notifications[index].id) }} 알림을 읽지 않은 상태라면 읽음 처리를 하는 함수입니다.들여쓰기를 없앨 수 있어서 없앴습니다.func readNotification(i..

iOS/Refactoring 2024.07.09

[UIKit/Refactoring] CollectionView Dynamic Header 개선하기 (SupplementaryView)

기존 구현된 헤더뷰 기존 구현한 헤더뷰의 모습입니다.스크롤이 위에 있을 때는 큰 헤더뷰를 보이다가, 스크롤을 내리면 헤더뷰를 고정하고 상단바처럼 동작하게 했습니다.  개선 목표1) 헤더뷰 변경 위치 정확하게 구하기사용자의 태그가 있을 때랑 없을 때 헤더뷰의 크기가 다릅니다.이는 정확히 언제 헤더뷰가 고정상태로 변경되어야 하는지에 대한 정보가 가변적이라는 것을 의미합니다.기존의 방식은, 특정 높이(고정값) 만큼 스크롤을 했을 때 헤더뷰의 상태를 바꾸는 방식으로 구현했는데, 이를 새로운 방식을 사용하거나 기존 방식을 수정해서 "가변적인 헤더 상태 변경 위치"를 정확히 잡는 것이 목표입니다. 위에 gif를 보면, 헤더뷰 상태가 변경될 때 셀들과 헤더 사이의 간격이 생기는 문제가 있습니다.상태 변경 높이가 잘못..

iOS/Refactoring 2024.06.29

[UIKit/Refactoring] getRelative... 코드 삭제 + 관련 문제 해결

동기 진행하고 있는 프로젝트에서, 그리고 이전 프로젝트에서 저는 항상 화면 크기를 고려해서 뷰의 동적인 사이즈를 계산했습니다.근데, 이 방식은 두 가지의 문제가 있었습니다.1) 협업하는 개발자는 이러한 방식을 사용하지 않는다.2) systemLayoutSizeFitting 함수를 사용하는 데에 문제가 있다. 1) 의 경우 사실 지금까지 무시해왔습니다. 각자 화면 별로 역할을 맡아왔기에, 굳이 통일성이 없다는 생각이 있었습니다.하지만 2) 의 경우 무시할 수 없었습니다. 그래서 getRelative 코드를 삭제하는 리팩토링을 진행하려 합니다. 리팩토링 getRelative... 함수는 다음과 같이 생겼습니다. 모든 화면에 대해서 같은 크기를 보여주는 것이 아닌, 화면의 너비와 높이를 고려해 비율에 맞는 뷰..

iOS/Refactoring 2024.06.24