iOS 타이머 앱 개선사항과 PickerView 구현

호씨·2025년 1월 13일
0

iOS 타이머 앱 개선사항과 PickerView 구현 🔄

UI/UX 주요 개선사항 💡

시간 선택 UI 개선: PickerView 도입

기존 버튼 방식에서 PickerView로 전환하여 사용성을 크게 개선했다.

private let timePickerView = UIPickerView()

private var hourArray: [Int] = Array(0...23)
private var minuteArray: [Int] = Array(0...59)
private var secondArray: [Int] = Array(0...59)

PickerView 설정 및 바인딩:

// PickerView 바인딩
viewModel.$hours
    .combineLatest(viewModel.$minutes, viewModel.$seconds)
    .receive(on: DispatchQueue.main)
    .sink { [weak self] hours, minutes, seconds in
        guard let self = self else { return }
        // 범위 체크 추가
        if hours < self.hourArray.count {
            self.timePickerView.selectRow(hours, inComponent: 0, animated: false)
        }
        if minutes < self.minuteArray.count {
            self.timePickerView.selectRow(minutes, inComponent: 1, animated: false)
        }
        if seconds < self.secondArray.count {
            self.timePickerView.selectRow(seconds, inComponent: 2, animated: false)
        }
    }
    .store(in: &cancellables)

PickerView delegate/dataSource 구현:

extension TimerView: UIPickerViewDelegate, UIPickerViewDataSource {
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 3    // 시, 분, 초
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case 0: return hourArray.count
        case 1: return minuteArray.count
        case 2: return secondArray.count
        default: return 0
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        let value: Int
        let suffix: String
        
        switch component {
        case 0:
            guard row < hourArray.count else { return nil }
            value = hourArray[row]
            suffix = "시간"
        case 1:
            guard row < minuteArray.count else { return nil }
            value = minuteArray[row]
            suffix = "분"
        case 2:
            guard row < secondArray.count else { return nil }
            value = secondArray[row]
            suffix = "초"
        default:
            return nil
        }
        
        return "\(value)\(suffix)"
    }
}

레이블 입력 UI 개선

  • 레이블 컨테이너 뷰 추가 (labelContainerView)
  • 좌측에 "레이블" 텍스트 추가 (labelTextLabel)
  • 우측에 이름 입력 필드 배치 (nameTextField)
  • 전체적인 디자인 통일성 향상

타이머 종료 옵션 추가

  • "타이머 종료 시" 버튼 추가 (timerEndButton)
  • 사용자 설정 가능한 종료 동작 UI 구현
  • 일관된 디자인으로 가독성 향상

테이블뷰 기능 강화

스와이프 삭제 기능이 추가되었다:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(style: .destructive, title: "삭제") { [weak self] (_, _, completion) in
        self?.viewModel.deleteTimer(at: indexPath.row)
        completion(true)
    }
    return UISwipeActionsConfiguration(actions: [deleteAction])
}

데이터 관리 개선 💾

타이머 데이터 삭제 로직 강화

func deleteTimer(at index: Int) {
    // CoreData와 로컬 데이터 동기화
    let timers = coreDataManager.fetchTimers()
    guard index < timers.count else { return }
    
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        self.coreDataManager.deleteTimer(timers[index])
        self.timerItems.remove(at: index)
    }
}

CoreData 저장 로직 개선

func deleteTimer(_ timer: TimerItem) {
    context.delete(timer)
    try? context.save() // 즉시 저장
}

코드 구조 개선 🏗

UI 컴포넌트 초기화 로직 분리

  • 각 UI 요소별 설정을 명확하게 구분
  • 코드 가독성과 유지보수성 향상
  • PickerView 관련 코드 모듈화

Auto Layout 최적화

SnapKit을 활용한 제약조건 설정:

private func setupConstraints() {
    timePickerView.snp.makeConstraints { make in
        make.top.equalTo(timerLabel.snp.bottom).offset(20)
        make.centerX.equalToSuperview()
        make.width.equalToSuperview()
        make.height.equalTo(200)
    }
    
    labelContainerView.snp.makeConstraints { make in
        make.top.equalTo(timePickerView.snp.bottom).offset(20)
        make.leading.trailing.equalToSuperview().inset(20)
        make.height.equalTo(40)
    }
    // ... 기타 제약조건
}
profile
이것저것 많이 해보고싶은 사람

0개의 댓글

관련 채용 정보