이전 고민
팩토리패턴으로 만든 UI요소의 반복적인 인스턴스 생성으로 인한 메모리사용 측면에서의 비효율
를 딱히 해결하지 못한 채 너무 바빠서 그냥 진행하게 되었고
이에 더하여
기존 UIComponent
import UIKit
// MARK: - 전체 앱의 뷰 통일감을 위해 ui컴포넌트를 제작
protocol LabelFactory {
func createLabel(with text: String, color: UIColor) -> UILabel
}
class BaseLabelFactory: LabelFactory {
func createLabel(with text: String, color: UIColor) -> UILabel {
let label = UILabel()
label.textAlignment = .left
label.text = text
label.textColor = color
return label
}
}
class TitleLabelFactory: BaseLabelFactory {
override func createLabel(with text: String, color: UIColor) -> UILabel {
let label = super.createLabel(with: text, color: color)// 매개변수는 레이블 각각이 다 다를 부분
label.font = UIFont.boldSystemFont(ofSize: 24) // 레이블의 성격따라 다를 부분
return label
}
}
class ContentLabelFactory: BaseLabelFactory {
override func createLabel(with text: String, color: UIColor) -> UILabel {
let label = super.createLabel(with: text, color: color)
label.font = .systemFont(ofSize: 16)
return label
}
}
이렇게 정의해두는 것은 UI요소 통일성의 목적도 있기 때문에 팀원들에게
아예 이 셋 이외에 다른 레이블 속성을 가지지마시오라고 못박아도 된다.
그러나 시간이 흐르면서 다양한 페이지의 레이아웃이 생기고 텍스트 정렬만 center로 가져가야한다던지 , 텍스트 자리가 충분하지 않아서 폰트사이즈나 굵기만 약간 변형되야한다던지 하는 경우가 많이 생기게 되었다.
class TestView: UIView {
private let 특수레이블 = 유연한레이블().createLabel(with: "저는 조금 달라야해요", color: .black, textAlign: .center, font: .boldSystemFont(ofSize: 16))
private let 보통레이블1 = 유연한레이블().createLabel(with: "특수한레이블", color: .black, textAlign: .left, font: .systemFont(ofSize: 16))
private let 보통레이블2 = 유연한레이블().createLabel(with: "보통보통", color: .black, textAlign: .left, font: .systemFont(ofSize: 16))
private let 보통레이블3 = 유연한레이블().createLabel(with: "그대로따르는레이블", color: .black, textAlign: .left, font: .systemFont(ofSize: 16))
특수 레이블 같은 경우가 생기므로서 정렬과 폰트속성을 받게해 대처할 수 있지만
나머지 보통레이블 같은 경우에는 쭉 일치될 부분인데 계속계속 필수적으로 작성해줘야됨
import UIKit
class LabelBuilder {
private var text: String = ""
private var color: UIColor = .black
private var font: UIFont = .systemFont(ofSize: 16)
private var align: NSTextAlignment = .left
// .. 기타 등등 속성을 커스텀할 일이 생기는 부분에 대해서 정의한다
func setText(_ text: String) -> LabelBuilder {
self.text = text
return self
}
func setColor(_ color: UIColor) -> LabelBuilder {
self.color = color
return self
}
func setFont(_ font: UIFont) -> LabelBuilder {
self.font = font
return self
}
func setAlign(_ align: NSTextAlignment) -> LabelBuilder {
self.align = align
return self
}
func build() -> UILabel {
let label = UILabel()
label.text = text
label.textAlignment = align
label.textColor = color
label.font = font
return label
}
}
class LabelFactory { //전역에서 공통적으로 쓰일 속성을 정의
static func titleLabel() -> LabelBuilder {
return LabelBuilder()
.setFont(.systemFont(ofSize: 24))
.setColor(.black)
.setAlign(.center)
}
static func contentLabel() -> LabelBuilder {
return LabelBuilder()
.setFont(.systemFont(ofSize: 16))
.setColor(.darkGray)
}
}
변형될 가능성이 있는 속성에 대해서 정의하고,
공통적으로 쓰일 라지타이틀 레이블, 본문 레이블을 정의해주되 특수한 경우가 생기면 변형이 가능하도록 만들 수 있다.
import SnapKit
import UIKit
class MainView: UIView {
private let titleLabel = LabelFactory.titleLabel()
.setText("제목")
.build()
private let customTitleLabel = LabelFactory.titleLabel()
.setText("조금특수한제목")
.setAlign(.right)
.build()
.
.
.
// 초기화 및 오토레이아웃설정
}
예를 들어 별도의 텍스트정렬을 원하지 않는다면 기본인 .center를 적용되게 하므로서 보일러 플레이트 코드 발생을 줄이고, 커스텀정렬이 필요하게 된다면 setAlign부분을 추가하여 커스텀할 수도 있게 하므로서 팀원들이 다양한 상황에 대처할 수 있는 방법도 제공한다.
또한 이전부터 고민하던 LabelFactory클래스의 인스턴스가 매번 새로이 생성되서 메모리 성능 면에서 비효율적이지 않은가 고민하던 문제는 , 인스턴스를 한번만 생성하게하는 싱글톤패턴을 적용하여 테스트해본다
//
// UIComponent.swift
// BuilerPattern
//
// Created by 임혜정 on 9/15/24.
//
import UIKit
class LabelBuilder {
private var text: String = ""
private var color: UIColor = .black
private var font: UIFont = .systemFont(ofSize: 16)
private var align: NSTextAlignment = .left
// .. 기타 등등 속성을 커스텀할 일이 생기는 부분에 대해서 정의한다
private var label: UILabel
init() {
self.label = UILabel()
}
func setText(_ text: String) -> LabelBuilder {
self.text = text
return self
}
func setColor(_ color: UIColor) -> LabelBuilder {
self.color = color
return self
}
func setFont(_ font: UIFont) -> LabelBuilder {
self.font = font
return self
}
func setAlign(_ align: NSTextAlignment) -> LabelBuilder {
self.align = align
return self
}
func build() -> UILabel {
let label = UILabel()
label.text = text
label.textAlignment = align
label.textColor = color
label.font = font
return label
}
func reset() {
label = UILabel()
}
}
class LabelFactory {
static let shared = LabelFactory()
private let builder: LabelBuilder
private init() {
self.builder = LabelBuilder()
}
func titleLabel() -> LabelBuilder {
builder.reset()
return LabelBuilder()
.setFont(.systemFont(ofSize: 24))
.setColor(.black)
.setAlign(.center)
}
static func contentLabel() -> LabelBuilder {
return LabelBuilder()
.setFont(.systemFont(ofSize: 16))
.setColor(.darkGray)
}
}
테스트용 50개의 레이블생성
싱글톤패턴적용전
싱글톤패턴적용후
왜 늘어나는거지?
인스턴스가 매번 새로이 생성되서 메모리적으로 비효율적이어 보인다는 문제의 개선방안으로 싱글톤패턴 적용은 적절치 않다. 빼는걸로
빌더패턴으로 변경되야하는 이유에 대해 팀원들을 설득하고 동의를 받아야한다. ㅋㅋ
아직 구현해야할 기능이 너무나 많아서 바쁜 와중에 view코드까지 수정하라고 하면 팀원들이 귀찮아질 것이 뻔한데 어떻게 설득할 것인가?