왜 빌더 패턴
- 빌더 패턴은 생성 패턴으로 코드의 결합도를 줄이고 재사용성을 높인다는 장점이 있습니다.
- 빌더 패턴은 사용하는 부분에서 파라미터를 모두 채워주지 않아도 필요한 값으로 생성이 가능합니다.
- 사용하는 곳에서 파라미터 값을 모두 채워주지 않아도 되어 코드가 간결해집니다.
- 한마디로 정리하면, Custom Alert을 편하게 사용(호출)하기 위해 빌더 패턴을 사용했습니다.
AlertBuilder
- Custom Alert을 구현하기 위해 우선 AlertBuilder 클래스를 만듭니다.
- AlertBuilder에는 Custom Alert을 띄울 baseViewController와 포함하고 있는 alertViewController가 필요합니다.
- alertTitle, message, addActionConfirm과 같은 Alert의 요소들도 필요합니다.
class AlertBuilder {
private let baseViewController: UIViewController
private let alertViewController = CustomAlertViewController()
private var alertTitle: String?
private var message: String?
private var addActionConfirm: AddAction?
}
- 그 다음에는 AlertBuilder의 init과 함수들을 구현했습니다.
- init에는 baseViewController 정도를 넣어줍니다.
- setTitle, setMessage, addActionConfirm은 각 프로퍼티에 값을 넣어주는 역할을 합니다.
- 특이점으로는 return으로 self를 리턴해서 Builder을 사용할때 이어서 호출 할 수 있게합니다.
class AlertBuilder {
...
init(viewController: UIViewController) {
baseViewController = viewController
}
func setTitle(_ text: String) -> AlertBuilder {
alertTitle = text
return self
}
func setMessage(_ text: String) -> AlertBuilder {
message = text
return self
}
func addActionConfirm(_ text: String, action: (() -> Void)? = nil) -> AlertBuilder {
addActionConfirm = AddAction(text: text, action: action)
return self
}
}
- AddAction은 구조체로 text와 action 프로퍼티를 갖고 있습니다.
struct AddAction {
var text: String?
var action: (() -> Void)?
}
- AlertBuilder의 마지막으로는 show 함수를 구현합니다.
- Alert 형태를 갖추도록 modalPresentationStyle과 modalTransitionStyle을 지정합니다.
- alertViewController에 프로퍼티 값을 전달하고, baseViewController 위에 alertViewController를 띄웁니다.
class AlertBuilder {
...
@discardableResult
func show() -> Self {
alertViewController.modalPresentationStyle = .overFullScreen
alertViewController.modalTransitionStyle = .crossDissolve
alertViewController.alertTitle = alertTitle
alertViewController.message = message
alertViewController.addActionConfirm = addActionConfirm
baseViewController.present(alertViewController, animated: true)
return self
}
}
CustomAlertViewController
- CustomAlertViewController를 구현할 차례입니다.
- 기본적인 프로퍼티 alertTitle, message, addActionConfirm을 선언합니다.
class CustomAlertViewController: UIViewController {
var alertTitle: String?
var message: String?
var addActionConfirm: AddAction?
}
class CustomAlertViewController: UIViewController {
...
private lazy var alertView = {
let view = UIView()
view.layer.cornerRadius = 16
view.backgroundColor = .secondarySystemBackground
return view
}()
private lazy var titleLabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
label.textAlignment = .center
label.text = alertTitle
return label
}()
private lazy var messageLabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 13)
label.textAlignment = .center
label.text = message
return label
}()
private lazy var horizontalDividerView = {
let view = UIView()
view.backgroundColor = .lightGray
return view
}()
private lazy var confirmButton = {
let button = UIButton()
button.setTitleColor(.label, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
button.setTitle(addActionConfirm?.text, for: .normal)
button.addTarget(self, action: #selector(pressed), for: .touchUpInside)
return button
}()
@objc func pressed() {
addActionConfirm?.action?()
dismiss(animated: true)
}
}
- 마지막으로, UI 요소들의 위치를 적절히 잡습니다.
- 레이아웃을 잡기 위해서는 많이 사용하는 SnapKit 라이브러리를 사용했습니다.
class CustomAlertViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
setViews()
}
private func setViews() {
view.backgroundColor = .systemBackground.withAlphaComponent(0.5)
view.addSubview(alertView)
alertView.snp.makeConstraints { make in
make.width.equalTo(300)
make.center.equalToSuperview()
}
alertView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.width.equalTo(260)
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(30)
}
alertView.addSubview(messageLabel)
messageLabel.snp.makeConstraints { make in
make.width.equalTo(260)
make.centerX.equalToSuperview()
make.top.equalTo(titleLabel.snp.bottom).offset(20)
}
alertView.addSubview(horizontalDividerView)
horizontalDividerView.snp.makeConstraints { make in
make.width.centerX.equalToSuperview()
make.height.equalTo(0.5)
make.top.equalTo(messageLabel.snp.bottom).offset(30)
}
alertView.addSubview(confirmButton)
confirmButton.snp.makeConstraints { make in
make.width.equalTo(300)
make.centerX.equalToSuperview()
make.height.equalTo(50)
make.top.equalTo(horizontalDividerView.snp.bottom)
make.bottom.equalToSuperview()
}
}
}
Custom Alert 사용
- Custom Alert은 원하는 ViewController에서 다음과 같이 호출 할 수 있습니다.
AlertBuilder(viewController: self)
.setTitle("알럿창")
.setMessage("알럿창의 메시지입니다")
.addActionConfirm("확인") {
print("확인을 눌렀습니다.")
}
.show()
결과물
- 이대로 실행해보면 다음과 같은 Custom Alert 창을 볼 수 있습니다.