Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IDLE-73] 휴대폰 번호 인증 UI및 기능 구현 #14

Merged
merged 12 commits into from
Jul 9, 2024

Conversation

J0onYEong
Copy link
Contributor

@J0onYEong J0onYEong commented Jul 8, 2024

변경된 부분

  • 회원가입 절차가 변경되어 관련 ViewController의 노출 순서를 수정했습니다.
  • 센터장 회원가입에 필요한 기초 UI구현을 완료하였습니다. (비밀번호, 아이디 정규표현식및 에러처리UI 미구현)
  • 센터장 로그인시 사용될 ViewModel을 구현하였습니다.
  • ViewModel이 View에 삽입되도록 DI 설정을 하였습니다.

UI 구현

디자인된 컴포넌트를 적용하여 화면을 구성하였습니다.
모든 컴포넌트는 고정된 크기를 가지는 것이 아닌 UILabel, UITextField와 같이 intrinsicSize를 가지는 뷰들을 기준으로 공간이 할당되도록 설계하였습니다. 이를 통해 후에 폰트크기가 변경되어도 효츌적으로 대응할 수 있습니다.

Image Description

ViewModel구현

센터장회원가입에 사용되는 ViewController들은 하나의 ViewModel을 공유합니다.

스크린샷 2024-07-08 오후 5 29 36

센터 회원가입을 구성하는 ViewController들은 하나의 Coordinator로 구현되어 있어 ViewModel은 위사진과 같이 전달됩니다.
해당 부분에 대해서는 추후에 개선방안을 논의해 보고 싶습니다.

같은 ViewModel을 다수에 ViewController가 공유하는 구조라 경계를 분리할 필요성을 느꼈습니다.
따라서 ViewModel이 Input, Output타입을 가지도록 ViewModelType이라는 인터페이스를 만들었습니다.

public protocol ViewModelType: AnyObject {
    
    associatedtype Input
    associatedtype Output
    
    var input: Input { get }
    
    func transform(input: Input) -> Output
}

ViewModel구현

스크린샷 2024-07-08 오후 5 33 50

Input의 경우 ViewController로부터 ViewModel이 전달받는 Observable로 구성됩니다.
Output의 경우 ViewModel가 ViewController에게 제공하는 Observable로 구성됩니다.

총 4개의 ViewController가 하나의 ViewModel을 사용하기에 각각의 ViewController가 ViewModel의 Input, Ouput접근에 제약이 필요하다고 생각하였습니다.
따라서 ViewController마다 필요한 Input, Output에 대한 프로토콜을 선언하였습니다.

아래사진은 가입자의 이름을 입력받는 ViewController코드의 일부입니다.

public protocol EnterNameInputable {
    var editingName: Observable<String>? { get set }
}

public protocol EnterNameOutputable {
    var nameValidation: PublishSubject<(isValid: Bool, name: String)>? { get set }
}

public class EnterNameViewController<T: ViewModelType>: DisposableViewController
where T.Input: EnterNameInputable & CTAButtonEnableInputable, T.Output: EnterNameOutputable {
    
    public var coordinator: Coordinator?
    
    private let viewModel: T

ViewController마다 선언한 인터페이스를 ViewModel이 채택하고 있습니다.

스크린샷 2024-07-09 오후 1 04 06

해당 ViewController의 경우 사용자 입력(이름)을 ViewModel로 전달하고 이름이 ViewModel이 유효한지 판단후, Ouput의 옵저버블을 통해 뷰컨트롤러에게 결과를 전달합니다.
input과 output의 연결은 ViewModel의 transform함수에서 진행됩니다.

image

인풋과 아웃풋을 각각 지정하니, 입력에 대한 유효성 판단과 로직이 ViewModel내부에서 진행됨을 분명히 할 수 있었습니다.
그리고 ViewController에서도 여러 부분에서 ViewModel을 다수 호출하는 것이 아닌, 하나의 함수에서 옵저버 패턴을 지정하는 것으로 모든 ViewModel과의 상호작용을 표현할 수 있어 코드 가독성이 좋아진 것 같습니다.

모든 옵저빙 패턴은 ViewModel의 transform(input)함수 그리고 각 뷰컨트롤러의 setObservable함수에서 진행됩니다.

스크린샷 2024-07-09 오전 11 32 53

스크린샷 2024-07-09 오전 11 32 37

DI 구현

개발한 ViewModel과 ViewModel에 필요한 UseCase, Repository의 DI작업을 완료하였습니다.
레이어 별로 구체타입이 인스턴스에 등록되도록 설정하였습니다.

  • 알게된점
    Swinject의 경우 Container인스턴스의 register매서드에 클로저를 전달하여 구체 인스턴스를 등록합니다.
    스크린샷 2024-07-09 오전 11 50 01
    초반에 모든 객체를 생성하여 등록하면, 사용하지 않는 구체타입 인스턴스도 생성되어 메모리 낭비가 발생할 수 있을 것이라 생각하였지만, 라이브러리 개발 코드를 살펴보고 브레이크 포인트를 찍어보니, 특정 객체를 사용할 때 해당 객체와 연관된 구체타입들(앞서 등록한 구체타입들)이 요청 시점에 생성됨을 확인할 수 있었습니다.
    아래 사진은 요청시점입니다.
    스크린샷 2024-07-09 오전 11 52 46

  • 궁금한점
    SWM-OSS 소마날씨앱을 살펴보면 ViewController까지 DI하는 것을 확인할 수 있었습니다. 현재 ViewController는 DI를 하지 않고 있습니다. 해당 구현에 대한 명확한 필요성을 느끼지 못했습니다. 해당 부분에 대해 문의드리고 싶습니다.

현재까지 구현 화면

Image Description

@J0onYEong J0onYEong marked this pull request as draft July 8, 2024 08:37
@J0onYEong J0onYEong marked this pull request as ready for review July 9, 2024 02:42
@J0onYEong J0onYEong merged commit e4aa149 into develop Jul 9, 2024
1 check passed
@J0onYEong J0onYEong deleted the feature/CenterRegister_phoneAuth branch July 9, 2024 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant