From 5cbea62496ce848207591b3782a2a86d5d6f96c2 Mon Sep 17 00:00:00 2001 From: KuKaH Date: Sat, 3 Jan 2026 03:37:13 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[chore]=20=EC=A4=91=EB=B3=B5=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=82=AD=EC=A0=9C(UITextField+)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extension/UITextField+.swift | 26 +++++++++++-- .../Presentation/Core/UITextField+.swift | 38 ------------------- 2 files changed, 22 insertions(+), 42 deletions(-) delete mode 100644 Smashing-Assignment/Presentation/Core/UITextField+.swift diff --git a/Smashing-Assignment/Extension/UITextField+.swift b/Smashing-Assignment/Extension/UITextField+.swift index b8372b1..74c36ca 100644 --- a/Smashing-Assignment/Extension/UITextField+.swift +++ b/Smashing-Assignment/Extension/UITextField+.swift @@ -1,12 +1,12 @@ // // UITextField+.swift -// NewCombine +// Smashing-Assignment // -// Created by JIN on 12/26/25. +// Created by 홍준범 on 12/26/25. // -import Combine import UIKit +import Combine extension UITextField { func textDidChangePublisher() -> AnyPublisher { @@ -17,4 +17,22 @@ extension UITextField { } } - +extension UITextField { + func addLeftPadding(_ width: CGFloat = 10) { + let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: self.frame.height)) + self.leftView = paddingView + self.leftViewMode = ViewMode.always + } + + func addRightPadding(_ width: CGFloat = 10) { + let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: self.frame.height)) + self.rightView = paddingView + self.rightViewMode = ViewMode.always + } + + /// 텍스트 필드에 좌우 패딩을 한 번에 추가합니다. + func addPadding(leftAmount: CGFloat = 10, rightAmount: CGFloat = 10) { + addLeftPadding(leftAmount) + addRightPadding(rightAmount) + } +} diff --git a/Smashing-Assignment/Presentation/Core/UITextField+.swift b/Smashing-Assignment/Presentation/Core/UITextField+.swift deleted file mode 100644 index 74c36ca..0000000 --- a/Smashing-Assignment/Presentation/Core/UITextField+.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// UITextField+.swift -// Smashing-Assignment -// -// Created by 홍준범 on 12/26/25. -// - -import UIKit -import Combine - -extension UITextField { - func textDidChangePublisher() -> AnyPublisher { - NotificationCenter.default - .publisher(for: UITextField.textDidChangeNotification, object: self) - .map { _ in self.text ?? "" } - .eraseToAnyPublisher() - } -} - -extension UITextField { - func addLeftPadding(_ width: CGFloat = 10) { - let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: self.frame.height)) - self.leftView = paddingView - self.leftViewMode = ViewMode.always - } - - func addRightPadding(_ width: CGFloat = 10) { - let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: self.frame.height)) - self.rightView = paddingView - self.rightViewMode = ViewMode.always - } - - /// 텍스트 필드에 좌우 패딩을 한 번에 추가합니다. - func addPadding(leftAmount: CGFloat = 10, rightAmount: CGFloat = 10) { - addLeftPadding(leftAmount) - addRightPadding(rightAmount) - } -} From 38e94bddfe0f432cfe01b25e15ff5622e3166a93 Mon Sep 17 00:00:00 2001 From: KuKaH Date: Sat, 3 Jan 2026 03:39:37 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[chore]=20HJB=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/{Core => HJB}/CombineViewController_HJB.swift | 0 .../Presentation/{Core => HJB}/CombineView_HJB.swift | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Smashing-Assignment/Presentation/{Core => HJB}/CombineViewController_HJB.swift (100%) rename Smashing-Assignment/Presentation/{Core => HJB}/CombineView_HJB.swift (100%) diff --git a/Smashing-Assignment/Presentation/Core/CombineViewController_HJB.swift b/Smashing-Assignment/Presentation/HJB/CombineViewController_HJB.swift similarity index 100% rename from Smashing-Assignment/Presentation/Core/CombineViewController_HJB.swift rename to Smashing-Assignment/Presentation/HJB/CombineViewController_HJB.swift diff --git a/Smashing-Assignment/Presentation/Core/CombineView_HJB.swift b/Smashing-Assignment/Presentation/HJB/CombineView_HJB.swift similarity index 100% rename from Smashing-Assignment/Presentation/Core/CombineView_HJB.swift rename to Smashing-Assignment/Presentation/HJB/CombineView_HJB.swift From 804aaf11d3f56ecdae7c5feddb9c22eb4adc5e8c Mon Sep 17 00:00:00 2001 From: KuKaH Date: Sat, 3 Jan 2026 05:35:42 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[feat]=20Combine=203=20=EA=B3=BC=EC=A0=9C?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Core/TabBarController.swift | 3 +- .../HJB/CombineViewController_HJB.swift | 122 +++++++++++++++--- .../Presentation/HJB/CombineView_HJB.swift | 20 ++- 3 files changed, 127 insertions(+), 18 deletions(-) diff --git a/Smashing-Assignment/Presentation/Core/TabBarController.swift b/Smashing-Assignment/Presentation/Core/TabBarController.swift index 9b8dfe3..3a09f7f 100644 --- a/Smashing-Assignment/Presentation/Core/TabBarController.swift +++ b/Smashing-Assignment/Presentation/Core/TabBarController.swift @@ -39,7 +39,8 @@ final class TabBarController: UITabBarController { case .jinjae: return JinJaeViewController() case .junbeom: - return CombineViewController_HJB() + let HJBviewModel = CombineViewModel_HJB() + return CombineViewController_HJB(viewModel: HJBviewModel) case .seungjun: return UIViewController() } diff --git a/Smashing-Assignment/Presentation/HJB/CombineViewController_HJB.swift b/Smashing-Assignment/Presentation/HJB/CombineViewController_HJB.swift index 76ed8dd..606fdb7 100644 --- a/Smashing-Assignment/Presentation/HJB/CombineViewController_HJB.swift +++ b/Smashing-Assignment/Presentation/HJB/CombineViewController_HJB.swift @@ -11,14 +11,79 @@ import Combine import Then import SnapKit +protocol InputOutputProtocol { + + associatedtype Input + associatedtype Output + + func transform(input: AnyPublisher) -> AnyPublisher +} + +class CombineViewModel_HJB: InputOutputProtocol { + + enum Input { + case firstTextFieldChanged(String) + case secondTextFieldChanged(String) + case buttonTapped + } + + enum Output { + case toggleButton(isEnabled: Bool) + case clearTextFields + } + + private let output: PassthroughSubject = .init() + private var cancellables = Set() + + private let firstTextSubject = CurrentValueSubject("") + private let secondTextSubject = CurrentValueSubject("") + + func transform(input: AnyPublisher) -> AnyPublisher { + input.sink { [weak self] event in + switch event { + case .firstTextFieldChanged(let text): + self?.firstTextSubject.send(text) + case .secondTextFieldChanged(let text): + self?.secondTextSubject.send(text) + case .buttonTapped: + self?.firstTextSubject.send("") + self?.secondTextSubject.send("") + self?.output.send(.clearTextFields) + } + }.store(in: &cancellables) + + Publishers.CombineLatest(firstTextSubject, secondTextSubject) + .map { first, second in + return first.count >= 5 && second.count >= 5 + } + .sink { [weak self] isEnabled in + self?.output.send(.toggleButton(isEnabled: isEnabled)) + }.store(in: &cancellables) + + return output.eraseToAnyPublisher() + } +} class CombineViewController_HJB: UIViewController { @Published var combineText: String = "" +// private let vm = CombineViewModel_HJB() + private let vm: CombineViewModel_HJB + + private let input: PassthroughSubject = .init() private var cancellables = Set() private let homeView = CombineView_HJB() + init(viewModel: CombineViewModel_HJB) { + self.vm = viewModel + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func loadView() { self.view = homeView } @@ -32,22 +97,29 @@ class CombineViewController_HJB: UIViewController { private func bind() { homeView.combineTextField.textDidChangePublisher() - .assign(to: &$combineText) + .sink { [weak self] text in + self?.input.send(.firstTextFieldChanged(text)) + }.store(in: &cancellables) - $combineText + homeView.secondCombineTextField.textDidChangePublisher() .sink { [weak self] text in - if text.count >= 5 { - self?.homeView.combineButton.isEnabled = true - self?.homeView.combineButton.backgroundColor = .systemBlue - self?.homeView.infoText.isHidden = true - - } else { - self?.homeView.combineButton.isEnabled = false - self?.homeView.combineButton.backgroundColor = .gray - self?.homeView.infoText.isHidden = false + self?.input.send(.secondTextFieldChanged(text)) + }.store(in: &cancellables) + + let output = vm.transform(input: input.eraseToAnyPublisher()) + + output + .receive(on: DispatchQueue.main) //이거 없애서 해보기 + .sink { [weak self] event in + switch event { + case .toggleButton(let isEnabled): + self?.homeView.combineButton.isEnabled = isEnabled + self?.homeView.combineButton.backgroundColor = isEnabled ? .systemBlue : .gray + case .clearTextFields: + self?.homeView.combineTextField.text = "" + self?.homeView.secondCombineTextField.text = "" } - } - .store(in: &cancellables) + }.store(in: &cancellables) } private func addTarget() { @@ -55,7 +127,27 @@ class CombineViewController_HJB: UIViewController { } @objc - private func combineButtonTapped() { - print("Tapped") + private func combineButtonTapped(_ sender: UIButton) { + input.send(.buttonTapped) } } + +// private func bind() { +// homeView.combineTextField.textDidChangePublisher() +// .assign(to: &$combineText) +// +// $combineText +// .sink { [weak self] text in +// if text.count >= 5 { +// self?.homeView.combineButton.isEnabled = true +// self?.homeView.combineButton.backgroundColor = .systemBlue +// self?.homeView.infoText.isHidden = true +// +// } else { +// self?.homeView.combineButton.isEnabled = false +// self?.homeView.combineButton.backgroundColor = .gray +// self?.homeView.infoText.isHidden = false +// } +// } +// .store(in: &cancellables) +// } diff --git a/Smashing-Assignment/Presentation/HJB/CombineView_HJB.swift b/Smashing-Assignment/Presentation/HJB/CombineView_HJB.swift index 3e89579..b47fa82 100644 --- a/Smashing-Assignment/Presentation/HJB/CombineView_HJB.swift +++ b/Smashing-Assignment/Presentation/HJB/CombineView_HJB.swift @@ -18,8 +18,15 @@ final class CombineView_HJB: UIView { $0.addPadding() } + var secondCombineTextField = UITextField().then { + $0.placeholder = "Combine2" + $0.layer.borderWidth = 1 + $0.layer.borderColor = UIColor.gray.cgColor + $0.addPadding() + } + var infoText = UILabel().then { - $0.text = "5글자 이상 입력해주세요" + $0.text = "두개의 텍스트 박스에 모두 5글자 이상 입력 시 삭제 가능" $0.textAlignment = .center } @@ -27,6 +34,7 @@ final class CombineView_HJB: UIView { $0.setTitle("Next", for: .normal) $0.setTitleColor(.black, for: .normal) $0.layer.cornerRadius = 8 + $0.backgroundColor = .gray } override init(frame: CGRect) { @@ -41,6 +49,7 @@ final class CombineView_HJB: UIView { private func setUI() { addSubview(combineTextField) + addSubview(secondCombineTextField) addSubview(infoText) addSubview(combineButton) } @@ -53,9 +62,16 @@ final class CombineView_HJB: UIView { $0.leading.trailing.equalToSuperview().inset(40) } - infoText.snp.makeConstraints { + secondCombineTextField.snp.makeConstraints { $0.centerX.equalToSuperview() $0.top.equalTo(combineTextField.snp.bottom).offset(20) + $0.height.equalTo(50) + $0.leading.trailing.equalToSuperview().inset(40) + } + + infoText.snp.makeConstraints { + $0.centerX.equalToSuperview() + $0.top.equalTo(secondCombineTextField.snp.bottom).offset(20) } combineButton.snp.makeConstraints {