접근 제어는 캡슐화를 구현하기 위한 가장 기본적인 단계입니다.
코드의 세부 구현을 숨기고 필요한 인터페이스만 노출함으로써, 우리는
- 코드의 안정성 향상
- 유지보수성 개선
- API의 명확성 제공
- 의도하지 않은 사용 방지
등의 이점을 얻을수 있습니다!
Module의 정의와 특징
엥 모듈이 뭐죠?
모듈은 코드 배포의 단위입니다. 하나의 모듈은 독립적으로 배포 가능한 코드의 묶음으로 생각하시면 됩니다.
// 다른 모듈에서 이렇게 import하여 사용
import UIKit // UIKit 모듈
import Foundation // Foundation 모듈
import YourCustomFramework // 사용자 정의 모듈
모듈은 논리적으로 연관된 기능들의 집합이며, 재사용 가능한 코드의 단위입니다.
예를 들면, UIKit은 UI 관련 기능들을, Foundation은 기본적인 데이터 타입과 기능들을 제공을 해주는 것이죠
Source File의 역할
소스 파일은 실제 코드가 작성되는 물리적인 파일입니다. 하나의 소스 파일은 다음과 같은 특징을 가집니다:
// MyView.swift
class MyView: UIView {
private var internalState: String = "" // 같은 파일 내에서만 접근 가능
fileprivate var sharedState: Int = 0 // 같은 파일 내에서 다른 타입에서도 접근 가능
}
// 같은 파일 내의 다른 타입
class MyViewHelper {
func helperMethod(view: MyView) {
view.sharedState = 1 // fileprivate이므로 접근 가능
// view.internalState = "" // private이므로 접근 불가
}
}
접근 제어자의 세부 분석
접근제어자에는
- Open
- Public
- Internal
- filePrivate
- private
이렇게 5가지가 있는데, 하나씩 살펴보자면
1. Open
가장 개방적인 접근 레벨입니다. 주로 프레임워크에서 상속과 오버라이딩을 허용하고자 할 때 사용됩니다.
// Framework A
open class OpenBaseClass {
open func openMethod() {}
}
특징:
- 다른 모듈에서 클래스 상속 가능
- 다른 모듈에서 메서드 오버라이드 가능
- 프레임워크의 핵심 클래스에서 주로 사용
- UIViewController, UIView 같은 UIKit의 기본 클래스들이 대표적인 예시
2. Public
외부 모듈에서 접근은 가능하지만, 상속과 오버라이딩은 제한됩니다.
public class NetworkManager {
public func fetchData() {}
}
특징:
- 다른 모듈에서 접근 가능
- 같은 모듈 내에서만 상속과 오버라이드 가능
- API를 제공하지만 수정은 제한하고 싶을 때 사용
- 주로 라이브러리의 공개 인터페이스를 정의할 때 사용
3. Internal
Swift의 기본 접근 제어자입니다. (생략가능)
class InternalClass { // 자동으로 internal
var property = 0
func method() {}
}
특징:
- 같은 모듈 내에서만 접근 가능
- 명시적으로 선언하지 않아도 됨
- 모듈 내부 구현에 주로 사용
- 앱 내부에서만 사용되는 대부분의 코드가 이 레벨
4. FilePrivate
같은 소스 파일 내에서만 접근을 허용합니다.
// UserManager.swift
class UserManager {
fileprivate var sharedData = "Shared"
}
class UserHelper {
func accessSharedData(manager: UserManager) {
print(manager.sharedData) // 같은 파일이므로 접근 가능
}
}
특징:
- 같은 파일 내에서만 접근 가능
- 관련된 타입들 간에 데이터를 공유할 때 사용
- 하나의 파일에서 완결되는 기능을 구현할 때 유용
5. Private
가장 제한적인 접근 레벨로, 정의된 범위 내에서만 사용 가능합니다.
class UserProfile {
private var userId: String = ""
private func validateId() {
// userId에 접근 가능
}
}
특징:
- 정의된 범위 내에서만 접근 가능
- 같은 파일이라도 다른 타입에서는 접근 불가
- 클래스의 내부 구현을 완전히 감추고 싶을 때 사용
- 데이터 은닉성을 가장 강력하게 보장
Open vs Public 차이
// Framework A
open class OpenBaseClass {
open func openMethod() {} // 다른 모듈에서 오버라이드 가능
public func publicMethod() {} // 같은 모듈에서만 오버라이드 가능
}
// Framework B
class SubClass: OpenBaseClass { // 다른 모듈에서도 상속 가능
override func openMethod() {} // 다른 모듈에서도 오버라이드 가능
// override func publicMethod() {} // 컴파일 에러! public 메서드는 다른 모듈에서 오버라이드 불가
}
Private vs FilePrivaite 차이
// UserProfile.swift
class UserProfile {
private var userId: String // 같은 타입 내에서만 접근 가능
fileprivate var userEmail: String // 같은 파일 내에서 접근 가능
private func validateUserId() {
// userId에 접근 가능
}
}
class UserProfileValidator {
func validate(profile: UserProfile) {
// profile.userId 접근 불가 (private)
// profile.userEmail 접근 가능 (fileprivate)
}
}