PLUB 개발회고 (2)

이건준·2023년 1월 21일
0

1. AutoLayout priority

1. 문제상황

  • 어떤 셀에 여러 UI를 집어넣을때 top, left, right, bottom을 전부 오토레이아웃을 잡아놓으면 우리가 원치않게 UI들이 늘어나거나 하는 경우가 종종있다

  • 그래서 어떤 UI를 만들때 sizeToFit과 left, top과 같이 일부분의 오토레이아웃만 잡아놓은 상태에서 보여주는걸 자주 하였다

  • 이번에도 위와 같이 동일하게 작업을 하다가 PR코멘트에서 해당 라벨의 텍스트가 많아질 경우 라벨을 덮고있던 셀을 오바하는 경우도 있다는 것을 발견하였다

2. 문제해결

  • 맨 처음 앞서 이야기했듯이 left, right를 둘다 오토레이아웃을 준다면 늘어나기때문에 고민할때 Reviewer분이 추천해주신 priority Hugging을 사용해보았다

Priority Hugging이란 ?

  • 우리가 어떤 UI에 대한 오토레이아웃을 걸때 항상 마지막에 건 UI는 딱 붙어있고 맨 처음 UI는 마지막 UI에 맞춰서 늘어진 형태를 볼 수 있을 것이다

  • 이처럼 각각 UI에 priority를 매겨서 우선순위가 더 높은 UI를 늘어나게 하거나 줄어들게 할 수 있는 속성이라 생각하면 된다

case .location:
      infoImageView.image = UIImage(named: "whiteLocation")
      infoImageView.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
      infoLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
  • 그래서 위처럼 우선순위가 더 높은 이미지뷰가 오토레이아웃에 맞춰서 레이아웃을 조정하다가 여유간격이 나왔을때 먼저 좁아짐으로써 라벨에 대한 텍스트가 늘어나게끔 조절하였다

  • 하지만 위와 같은 방법도 UI 구조상 틀린 코드는 아니지만 근본적인 문제였던 오바되는 문제를 해결하지는 못하였다

AutoLayout lessThan

  • 결국 셀을 침범하지못하기위해선 셀과 UI에 대한 오토레이아웃을 걸어줌으로써 침범하지못하게 하는 방법밖에 없었다

  • 이런 상황에서 equalTo나 equalSuperView처럼 딱 고정시키는게 아닌 lessThan이라는 오토레이아웃코드를 발견하였다

categoryInfoListView.snp.makeConstraints {
      $0.width.lessThanOrEqualTo(self.frame.width - 20)
    }
  • top, left에 대한 제약을 줌과 동시에 width에 대한 오토레이아웃을 lessThan을 이용하여 걸어줌으로써 셀을 침범하지않음과 동시에 UI가 늘어나지않는 내가 원하는 UI가 완성되었다

2. withLatestFrom, distinctUntilChanged

1. 문제상황

  • Rx를 아예 안써본것은 아니지만 확실히 항상 써오던 코드는 대략 어떨때 사용하는지 감이 오지만 그 외의 코드들은 잘 감이 안온다

  • 이번 PLUB이라는 프로젝트를 하면서 자주 사용하면서도 이번에 사용법에 대해 조금이나마 자세히 알게 된 Operator가 위 2개이다

  • 내가 마주하게 된 상황은 셀을 단 하나라도 클릭했을 경우 floating Button이 enabled하게 모든 셀을 클릭하지않았을 경우에 unEnabled하게 변경하는 부분이였다

  • 위와 같은 상황에서 클릭할때마다 카운트 수를 viewModel에 가지고있고 양수일땐 enabled true를 0일때 enabled false하게 구현하고 싶었다

2. 문제해결

  • 위 상황때 withLatestFrom연산자를 통해서 클릭했을때만 second가 바라보고있는 최신값을 방출하기에 위와 같은 상황에 유용하게 사용할 수 있었다
selectingDetailCell.withLatestFrom(selectingDetailCellCount)
      .map{ $0 + 1 }
      .subscribe(onNext: selectingDetailCellCount.onNext(_:))
      .disposed(by: disposeBag)
    
    deselectingDetailCell.withLatestFrom(selectingDetailCellCount)
      .map{ $0 - 1 }
      .subscribe(onNext: selectingDetailCellCount.onNext(_:))
      .disposed(by: disposeBag)
  • withLatestFrom연산자는 마지막에 result selector라고 방출값을 트리거가 가지고있는 값 또한 받게 할 수 있다

distinctUntilChanged

  • 이 연산자는 동일한 방출값일때 무시하게 하는 아주 유용한 연산자 중 하나라고 생각한다

  • 헌데 이번 프로젝트에서 기본 제공해주는 타입이 아닐 경우에 예를 들어 커스텀 구조체와 같은 데이터를 비교해야할 경우 직접 어떠한 경우에 무시할지를 코드해주어야한다

  • 하지만 이번에 이 연산자에 대한 부분을 코드할때 Xcode에서 영문모를 오류투성이였고 나는 이를 편리하게 사용할 방법을 찾아내었다

struct QuestionStatus: Equatable {
  let id: Int
  let isFilled: Bool
  
  static func == (lhs: QuestionStatus, rhs: QuestionStatus) -> Bool {
    return lhs.id == rhs.id && lhs.isFilled == rhs.isFilled
  }
}
  • 바로 Equatable 프로토콜을 채택하여 같은 값인지에 대한 정의를 내려주는것이다. 물론 너무나 당연한 이야기였지만 이 부분에 대해서 어지간히 골치아팠다...
entireQuestionStatus
          .distinctUntilChanged()
          .subscribe(onNext: { current in
            let isAllChecked = current.filter{ $0.isFilled == false }.count == 0
            isActivating.onNext(isAllChecked)
          })
          .disposed(by: disposeBag)
  • Equatable에 대한 정의를 내려줌으로써 distinctUntilChanged를 깔끔히 사용할 수 있는 모습 !!

3. UITextField에 대한 이벤트

  • 기존에 UITextField와 UITextView에 대해 rx와 연동하는 코드에서 매번 아래와 같이 작성해왔다
textField.rx.text
.subscribe(onNext: {

})
.disposed(by: disposeBag)

textView.rx.text
.subscribe(onNext: {

})
.disposed(by: disposeBag)
  • 헌데 이번 프로젝트를 진행하면서 확실히 해당 UI에 텍스트를 입력했을때에만 값을 가져와야하는 코드를 써야만 했고 위 코드는 나의 의도와는 별개로 잘 동작하지않았다

이유가 무엇일까 ??

  • 기본적으로 rx.text는 포커싱, 텍스트 입력, 언포커싱과 같이 다양한 이벤트들에 대해 반응하여 그 당시 UI의 텍스트에 대한 값을 내려보내준다

  • 즉, editingChanged같은 실제 텍스트가 변할때만 값의 변동을 원하는 나의 경우 이에 맞지않았다

textField.rx.text
.orEmpty
.skip(1)
.distinctUntilChanged()
.filter { $0.count != 0 }
  • 나의 해결방법으로 위와 같은 코드를 짜야하는데 하나하나 살펴보겠다

1. orEmpty

  • 이 부분은 rx.text로 내려오는 String값이 Optional이기에 이를 벗겨내기위한 연산자로써 사용된다

2. skip(1)

  • 이 부분은 textField.rx.text가 동작하는 이벤트들이 [allEditingEvents, valueChanged] 2개의 동작을 이행하기때문에 처음 구독되었을때 방출되는 값을 skip연산자를 이용해 벗겨내는것이다

3. distinctUntilChanged()

  • 이 연산자는 동일한 값을 방출할 경우에 막아주는 아주 유용한 연산자이다, 앞서 말한 textField.rx.text가 동작하는 이벤트들이 있기에 포커싱, 언포커싱때에도 값이 방출되는 경우를 막기위해 사용해준다

0개의 댓글