
접근 제어(Access Control)는 다른 소스 파일과 모듈 등에서 코드 접근에 대해 제한하는 기능이다.
접근 제어를 통해 코드의 세부 구현을 숨길수도 있으며, 어디에서까지 해당 코드에 접근할지 범위를 설정할 수 있다.
우리가 흔히 알고있는 Swift의 접근제어자는 5가지가 있다.
- `private` : 선언된 파일 내에서만 접근 가능
- `fileprivate` : 같은 파일 내 모든 스코프에서 접근 가능
- `internal` : 같은 모듈(타겟) 내에서만 접근 가능
- `public` : 다른 모듈에서도 접근 가능
- `open` : public과 같으면서, 서브클래싱 및 오버라이드까지 허용
그런데 Swift5.9에서 `package`라는 새로운 접근제어자가 등장했다.
이번 글에서는 이 package 접근제어자에 대해 알아보도록 하겠다.
package 접근제어자란?
package의 접근 제어 범위는 SPM으로 구성된 하나의 패키지 내부에서만 접근을 허용한다.
즉, package 접근제어자는 패키지 안에 여러 모듈이 있을 때, 이 모듈 사이에서만 접근이 가능하게 하는 것으로,
패키지 외부에 코드를 공유하지 않는 다는 특징이 있다.
그럼, package 접근제어자가 등장한 이유에 대해 알아보도록 하자.
package 접근제어를 사용할 수 없었을때는, 패키지 내의 다른 모듈에서 코드에 접근하기 위해 public 접근제어자를 사용했을 것이다.
// gamePkg 내의 Engine 모듈
public struct MainEngine {
public init() { ... }
// public으로 선언
public var stats: String { ... }
// Game 모듈에서만 접근 가능하도록 public으로 선언된 헬퍼 펑션
public func run() { ... }
}
// gamePkg 내의 Game 모듈
import Engine
public func play() {
MainEngine().run() // 같은 gamePkg 내부이기 때문에 run 펑션에 접근 가능
}
그러나, 이렇게 public으로 선언된 코드는 패키지 외부에서도 접근 가능하다는 문제가 있었다.
// appPkg 내의 클라이언트 App
import Game
import Engine
let engine = MainEngine()
engine.run() // App 에서도 run 펑션에 접근 가능
Game.play()
print(engine.stats) // state에 접근 가능
이렇게 됐을때의 문제점은 다음과 같다.
클라이언트 App 에서 패키지 내부의 코드에 접근 할 수 있다는 것은, 이 SPM을 쓰는 모든 클라이언트 App 에서 내부 코드에 접근할 수 있다는 뜻이고, 이는 곧 의도치 않게 패키지 내부의 API등이 노출될 수 있다는 위험이 존재한다는 것이다.
내부 API가 노출된다는건, SPM을 사용하는 사용자가 내부 구현에 의존하게 되고, 패키지를 만드는 쪽에서 마음대로 구조를 바꾸거나 삭제할 수 없는 등 유연성이 떨어질 수 있다.
Swift5.9에서 package 접근제어자가 등장한 이유가 바로 이러한 문제를 해결하기 위해서이다.
package를 사용한 개선
위의 public으로 선언된 코드들을, package로 다음과 같이 변경해볼 수 있다.
state 프로퍼티와 run 펑션을 package로 선언하면 다음과 같이 같은 패키지 내의 다른 모듈에서 접근해서 사용할 수 있다.
// gamePkg 내의 Engine 모듈
package struct MainEngine {
// package 접근제어자로 초기화도 패키지 내부 전용으로 지정
package init() { ... }
// 패키지 내부에서만 읽을 수 있는 stats 프로퍼티
package var stats: String {
// ...
return "Engine 상태 정보"
}
// Game 모듈에서도 접근 가능한 run 함수
package func run() {
print("Engine 가동 중…")
}
}
// gamePkg 내의 Game 모듈
import Engine
// App 쪽에 노출할 public API
public func play() {
let engine = MainEngine() // 같은 패키지 내이므로 접근 가능
engine.run() // ✅ package 멤버 호출 가능
print(engine.stats) // ✅ package 멤버 호출 가능
}
그리고, 외부 클라이언트 앱에서는 public으로 선언된 play 펑션에는 접근할 수 있으나,
package로 선언된 MainEngine이나, run, state에는 접근 할 수 없다.
// appPkg 내의 클라이언트 App
import Game
import Engine
play() // ✅ Game.play()는 public이므로 호출 가능
let engine = MainEngine() // ❌ 오류: 'MainEngine' initializer is inaccessible due to 'package' protection level
engine.run() // ❌ 오류: 'run()' is inaccessible due to 'package' protection level
print(engine.stats) // ❌ 오류: 'stats' is inaccessible due to 'package' protection level
이렇게 package를 도입하면 위에서 언급한 public으로 선언했을 때의 문제를 해결할 수 있다.
- 배포 단위 경계: 모든 클라이언트에 노출 -> 패키지 내부에만 공개하고 외부에는 숨김
- API 유지보수: 의도치 않은 의존성 발생 -> 외부에 영향을 받지 않고, 내부에서 리펙토링 가능
*참고자료
https://github.com/swiftlang/swift-evolution/blob/main/proposals/0386-package-access-modifier.md
swift-evolution/proposals/0386-package-access-modifier.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
github.com
https://green1229.tistory.com/453
New access modifier - package
안녕하세요. 그린입니다 🍏 이번 포스팅에서는 Swift 5.9에서 새로 나온 접근 제어자인 package에 대해 알아보겠습니다 🙋🏻 나온 배경 원래 기존에 접근제어자라고 하면 흔히 알고 있는 5가지가
green1229.tistory.com
https://youngkdevlog.tistory.com/70
Swift 6.0 접근제어자 Access Control
우선 우리가 잘 알고 있듯이 swift의 접근제어자는 다음과 같이 6개가 있습니다. 5개라고 알고 있는 사람도 많겠지만, Swift 5.9 부터 package 접근제어자가 추가되어 6개가 되었습니다.Swift는 코드 내
youngkdevlog.tistory.com
https://blog.eidinger.info/a-new-access-modifier-in-swift-package
A new access modifier in Swift: package
Detailed explanation about Swift's new package access modifier introduced in Swift 5.9
blog.eidinger.info
'iOS > Swift' 카테고리의 다른 글
| [iOS/Swift] 별도의 프로세스 - PHPicker를 사용할때 권한요청이 필요 없는 이유 (0) | 2025.04.07 |
|---|---|
| [iOS/Swift] Mock과 Stup은 다르다고? - Test Double (0) | 2025.04.03 |
| [iOS/Swift] Swift의 UnitTest 살펴보기 (0) | 2025.03.31 |
| [iOS/Swift] 컴파일러 최적화 관점에서 본 Opaque Type (0) | 2025.03.28 |
| [iOS/Swift] Kingfisher를 쓰지 않고 이미지 캐싱 구현하기 - NSCache (0) | 2025.03.25 |