Swift에서 extensions는 표준 유형(예: String, Array) 및 사용자 정의 유형을 상속이나 원래 소스 코드를 변경하지 않고 확장할 수 있는 수단으로 등장했습니다. 이를 통해 새로운 메서드, 계산 속성, 프로토콜 준수 및 프로토콜에 대한 적합성을 추가하면서도 코드의 가독성과 일관된 구조를 유지할 수 있습니다.
문제는 extensions의 과도하거나 무질서한 사용으로 인해 발생합니다: 원래 유형의 동작을 쉽게 잃을 수 있으며, 이름 충돌이 발생하거나, 특히 대규모 프로젝트나 외부 라이브러리를 연결할 때, 무엇이 어디에서 오는지를 추적하는 것이 더 어려워질 수 있습니다.
해결책은 명확한 구조, 의미적으로 그룹화된 extensions, 명확한 문서화 및 기존 이름과의 충돌 방지 그리고 필요한 경우 접근 범위 제한(예: fileprivate 또는 internal)을 갖는 것입니다.
코드 예:
extension String { var isEmail: Bool { return self.contains("@") && self.contains(".") } func trimmed() -> String { return trimmingCharacters(in: .whitespacesAndNewlines) } }
주요 특징:
extension을 통해 저장 속성을 추가할 수 있나요?
아니요, extension은 계산된 속성과 메서드만 추가할 수 있습니다. 저장된 속성(stored properties)은 extension을 통해 추가할 수 없습니다. 시도해 보세요 — 컴파일러가 즉시 오류를 발생시킬 것입니다.
서로 다른 파일의 두 개의 다른 extension에서 동일한 이름의 메서드를 선언하면 어떻게 됩니까?
이름 충돌이 발생하며, Swift는 어떤 메서드를 호출해야 할지 판단할 수 없어 컴파일 단계에서 오류가 발생합니다.
extensions가 내부에서만 보이는 private 메서드를 구현할 수 있나요?
네, private으로 메서드를 선언하면 해당 extension과 해당 메서드를 선언한 파일 내에서만 볼 수 있습니다(파일이 fileprivate일 경우).
extension Int { private func isEvenInternal() -> Bool { return self % 2 == 0 } func publicCheckEven() -> Bool { return isEvenInternal() } }
** 부정적인 사례**
대규모 프로젝트에서 String에 대한 메서드가 이메일 검증부터 JSON 파싱까지 모든 기능을 추가하는데 사용됩니다. 1년 후에는 아무도 어떤 기능이 어디서 오는지 이해할 수 없습니다: 메서드 이름이 충돌하고, 누군가 새로운 함수를 추가하여 옛 기능을 모르고 의존성의 동작을 깨뜨립니다.
장점:
단점:
** 긍정적인 사례**
팀은 논리적인 그룹을 위해 extensions를 사용합니다: 검증을 위한 별도의 extension, 형식을 위한 별도의 extension, 내부에 비공식 도우미를 포함합니다. 모든 메서드는 문서화되어 있으며, 새로운 메서드의 사용이 논의되며, 코드 리뷰가 있습니다.
장점:
단점: