[UIKit] UIView의 tag 사용이 안티패턴인 이유와 대안

UIKitiosSwift
avatar
2025.03.11
·
5 min read

UIKit에서 UIButton.tag를 활용하여 버튼을 구분한 적이 있었는데, 코드리뷰를 통해 안티패턴임을 알게 되었다. 이 글에 tag를 사용하는 것이 왜 문제가 되는지, 대안은 무엇이 있는지 기록한다.


UIButton.tag란?

UIKit에서 tag는 UIView의 속성으로, 개발자가 정수(Int) 값을 부여하여 특정 뷰를 식별할 수 있도록 설계되었다.

let button = UIButton()
button.tag = 1  // 특정 버튼을 식별하기 위한 tag 값 할당

tag는 단순한 정수 값이므로 여러 개의 버튼을 쉽게 구분할 수 있지만, 이는 가독성과 유지보수성 측면에서 심각한 문제를 유발할 수 있다.

tag를 사용하는 것이 안티패턴인 이유

매직 넘버(Magic Number) 문제

tag값은 정수형이므로, 코드에서 해당 숫자가 무엇을 의미하는지 명확하지 않다.

@IBAction func buttonTapped(_ sender: UIButton) {
    if sender.tag == 1 {
        print("로그인 버튼 클릭")
    } else if sender.tag == 2 {
        print("회원가입 버튼 클릭")
    }
}

위 코드에서 tag == 1tag == 2가 무엇을 의미하는지 즉시 이해하기 어렵다.

유지보수의 어려움

  • 새로운 버튼이 추가되거나 변경되면 모든 관련 코드를 찾아서 수정해야 한다.

  • 같은 tag값을 실수로 여러 뷰에 설정하면 예상치 못한 버그가 발생할 수 있다.

  • tag값을 확인하려면 일일이 코드에서 해당 숫자가 의미하는 바를 찾아야 한다.

타입 안정성이 부족함

tag는 단순히 Int이므로, 버튼이 특정 기능과 연결된다는 명확한 보장이 없다.

if sender.tag == 1001 { // 이 값이 무엇을 의미하는지 불명확함
    performAction()
}

Swift는 타입 안정성을 중요하게 여기는 언어이지만, tag를 사용하면 Int값만으로 UI 요소를 구별해야 하므로 타입 안정성이 깨진다.

tag의 대안

버튼에 IBAction 직접 연결하기

  • Xcode의 Interface Builder에서 버튼마다 별도의 IBAction을 연결하면 가독성이 높아진다.

  • tag가 없어도 어떤 버튼이 눌렸는지 명확하게 알 수 있다.

@IBAction func loginButtonTapped(_ sender: UIButton) {
    print("로그인 버튼 클릭")
}

@IBAction func signUpButtonTapped(_ sender: UIButton) {
    print("회원가입 버튼 클릭")
}

enumswitch문 사용

  • UIButtontag 대신 enum을 활용하면 코드의 명확성이 증가한다.

  • tag를 그대로 사용하면서도 코드 가독성을 높일 수 있다.

enum ButtonType: Int {
    case login = 1
    case signUp = 2
}

@IBAction func buttonTapped(_ sender: UIButton) {
    guard let type = ButtonType(rawValue: sender.tag) else { return }
    
    switch type {
    case .login:
        print("로그인 버튼 클릭")
    case .signUp:
        print("회원가입 버튼 클릭")
    }
}

UIButton에 식별자 속성 추가

  • tag 대신 UIButton에 직접 연관된 문자열 속성을 추가하여 사용할 수도 있다.

  • tag를 그대로 사용하면서도 코드 가독성을 높일 수 있다.

class IdentifiableButton: UIButton {
    var identifier: String?
}

@IBAction func buttonTapped(_ sender: IdentifiableButton) {
    if sender.identifier == "login" {
        print("로그인 버튼 클릭")
    } else if sender.identifier == "signUp" {
        print("회원가입 버튼 클릭")
    }
}






- 컬렉션 아티클