Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,28 @@ private struct PickerViewRepresentable: UIViewRepresentable {
}

let row = selection - range.lowerBound
picker.selectRow(row, inComponent: 0, animated: true)
picker.selectRow(row, inComponent: 0, animated: false)

DispatchQueue.main.async {
self.findAndConnectScrollViews(in: picker, coordinator: context.coordinator)
}
Comment on lines +46 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

내부 UIPickerView 구조에 의존하는 구현

UIPickerView의 내부 서브뷰 계층 구조는 비공개 API이므로, iOS 버전 업데이트 시 UIScrollView를 찾지 못할 수 있습니다. 이 접근 방식은 현재 동작하지만 향후 iOS 업데이트에서 깨질 수 있으므로, 스크롤 뷰를 찾지 못하는 경우에 대한 폴백(fallback) 로직 추가를 권장합니다.

🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift`
around lines 46 - 48, 현재 findAndConnectScrollViews(in: picker, coordinator:
context.coordinator)가 UIPickerView 내부에서 UIScrollView를 찾아 연결하는데 내부 구조에 의존하므로, 찾지
못할 때의 폴백을 추가하세요: 변경할 위치는 findAndConnectScrollViews(in:coordinator:) 구현부와
호출부(DispatchQueue.main.async 블록)이며, 함수가 UIScrollView를 찾지 못하면 false를 반환하거나
completion 을 호출하도록 하고, 그 경우 UIPickerView 자체에 UIPanGestureRecognizer 또는
UITapGestureRecognizer를 추가하여 context.coordinator(예:
coordinator.handlePan/handleTap 같은 기존 핸들러)를 연결하도록 구현하세요; 이렇게 하면 내부 서브뷰 탐색에 실패할
때도 사용자 입력을 캡처할 수 있습니다.


return picker
}

private func findAndConnectScrollViews(in view: UIView, coordinator: Coordinator) {
for subview in view.subviews {
if let scrollView = subview as? UIScrollView {
coordinator.originalScrollViewDelegate = scrollView.delegate
scrollView.delegate = coordinator
Comment on lines +55 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와이거개고능하네요

}
findAndConnectScrollViews(in: subview, coordinator: coordinator)
}
}
Comment on lines +53 to +61
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

여러 UIScrollView가 존재할 경우 원본 델리게이트 손실 가능

UIPickerView 내부에 여러 UIScrollView가 있을 경우, originalScrollViewDelegate가 마지막에 발견된 스크롤 뷰의 델리게이트로 덮어씌워집니다. 첫 번째 스크롤 뷰를 찾은 후 탐색을 중단하거나, 각 스크롤 뷰별로 원본 델리게이트를 저장하는 것이 안전합니다.

♻️ 제안된 수정사항
 private func findAndConnectScrollViews(in view: UIView, coordinator: Coordinator) {
     for subview in view.subviews {
         if let scrollView = subview as? UIScrollView {
             coordinator.originalScrollViewDelegate = scrollView.delegate
             scrollView.delegate = coordinator
+            return  // 첫 번째 스크롤 뷰만 연결
         }
         findAndConnectScrollViews(in: subview, coordinator: coordinator)
     }
 }
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift`
around lines 53 - 61, 현재 findAndConnectScrollViews(in:coordinator:)가 여러
UIScrollView를 순회할 때 coordinator.originalScrollViewDelegate를 덮어써 첫 발견 델리게이트를 잃을 수
있습니다; 수정 방법은 Coordinator에 원본 델리게이트를 하나가 아닌 스크롤뷰별로 저장하도록 변경하고(예:
originalScrollViewDelegates: [UIScrollView: UIScrollViewDelegate?])
findAndConnectScrollViews에서는 각 scrollView에 대해
coordinator.originalScrollViewDelegates[scrollView] = scrollView.delegate 후
scrollView.delegate = coordinator로 설정하도록 바꾸거나, 단순히 첫번째 UIScrollView를 찾은 뒤 탐색을
중단하도록 로직을 변경하여 덮어쓰기를 방지하세요; 이후 원복 로직(예: disconnect/teardown)도 Coordinator의 매핑을
사용해 각 스크롤뷰의 원본 델리게이트를 복원하도록 업데이트해야 합니다.


func updateUIView(_ uiView: UIPickerView, context: Context) {
guard !context.coordinator.isScrolling else { return }

let row = selection - range.lowerBound
if uiView.selectedRow(inComponent: 0) != row {
uiView.selectRow(row, inComponent: 0, animated: true)
Expand All @@ -59,8 +75,11 @@ private struct PickerViewRepresentable: UIViewRepresentable {
}

extension PickerViewRepresentable {
class Coordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
class Coordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource, UIScrollViewDelegate {
var parent: PickerViewRepresentable
private let rowHeight: CGFloat = 44.adjustedH
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

행 높이 상수 중복

rowHeight가 80번째 줄과 115번째 줄(pickerView(_:rowHeightForComponent:))에서 각각 정의되어 있습니다. 하나의 상수로 통일하면 유지보수성이 향상됩니다.

♻️ 제안된 수정사항
 func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
-    44.adjustedH
+    rowHeight
 }
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift`
at line 80, There is a duplicated row height value — remove the local
constant/duplicate definition inside pickerView(_:rowHeightForComponent:) and
make that method return the single property rowHeight (private let rowHeight:
CGFloat = 44.adjustedH) so the component uses the central constant; update any
references in pickerView(_:rowHeightForComponent:) to use rowHeight and delete
the redundant duplicate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인부탁~~

var isScrolling: Bool = false
weak var originalScrollViewDelegate: UIScrollViewDelegate?

init(_ parent: PickerViewRepresentable) {
self.parent = parent
Expand All @@ -75,13 +94,14 @@ extension PickerViewRepresentable {
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
isScrolling = false
parent.selection = parent.range.lowerBound + row
}

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
pickerView.subviews.forEach { subview in
subview.backgroundColor = .clear
}
subview.backgroundColor = .clear
}

let label = (view as? UILabel) ?? UILabel()
label.text = "\(parent.range.lowerBound + row)"
Expand All @@ -98,5 +118,47 @@ extension PickerViewRepresentable {
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
60.adjustedW
}

private var initialContentOffset: CGFloat = 0
private var initialRow: Int = 0

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
isScrolling = true
initialContentOffset = scrollView.contentOffset.y
initialRow = parent.selection - parent.range.lowerBound
originalScrollViewDelegate?.scrollViewWillBeginDragging?(scrollView)
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
originalScrollViewDelegate?.scrollViewDidEndDragging?(scrollView, willDecelerate: decelerate)
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
originalScrollViewDelegate?.scrollViewDidEndDecelerating?(scrollView)
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개행 한번만여

originalScrollViewDelegate?.scrollViewWillEndDragging?(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
originalScrollViewDelegate?.scrollViewDidScroll?(scrollView)

guard isScrolling else { return }

let deltaOffset = scrollView.contentOffset.y - initialContentOffset
let deltaRow = Int(round(deltaOffset / rowHeight))
let newRow = initialRow + deltaRow
let clampedRow = max(0, min(newRow, parent.range.count - 1))
let newSelection = parent.range.lowerBound + clampedRow
Comment on lines +149 to +153
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와우어렵네요 고능하다

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와우띵..


if parent.selection != newSelection {
parent.selection = newSelection
}
}

func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
originalScrollViewDelegate?.scrollViewDidEndScrollingAnimation?(scrollView)
}
}
}