소피it블로그

[Swift 공식문서] Access Control 정리 (기본) 본문

개발_iOS/스위프트

[Swift 공식문서] Access Control 정리 (기본)

sophie_l 2022. 8. 22. 21:44

https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

 

Access Control — The Swift Programming Language (Swift 5.7)

Access Control Access control restricts access to parts of your code from code in other source files and modules. This feature enables you to hide the implementation details of your code, and to specify a preferred interface through which that code can be

docs.swift.org

 

스위프트는 코드 내부의 엔티티에 대해 사용할 수 있는 액세스 레벨을 총 다섯 가지 제공한다. 이 액세스 레벨들은 엔티티가 정의된 소스 파일에 따라 상대적이며, 해당 소스 파일이 포함된 모듈에 따라서도 상대적이다.

 

  • open accesspublic access: 엔티티 자신을 정의하는 모듈 내의 모든 소스 파일과, 해당 모듈을 임포트한 다른 모듈의 소스 파일에서 전부 접근이 가능하다. 보통 open이나 public 액세스는 프레임워크에 퍼블릭 인터페이스를 구체화할때 사용한다. 오픈과 퍼블릭 액세스의 차이는 밑에서 다시 설명한다.
  • internal access: 엔티티들을 정의하는 모듈 내부의 소스 파일에서는 사용될 수 있으나, 그 모듈 외부의 소스 파일에서는 사용할 수 없다. 보통 인터널 액세스는 앱이나 프레임워크의 내부 구조를 정의할 때 사용한다.
  • file-private access: 엔티티를 정의하는 소스 파일 내부에서만 사용할 수 있다. 특정 파일 내부에서 쓰이는 기능의 세부사항에 대한 구체적인 구현을 감추고 싶을 때 file-private를 사용하라.
  • private access: 엔티티를 감싸는 선언부 내에서, 그리고 같은 파일 내의 해당 선언에 대한 익스텐션에서만 해당 엔티티를 사용할 수 있다. 특정 기능에 대해서 그 세부 사항이 해당 선언부 내에서만 사용될 경우, 세부 구현을 감추기 위해 private 액세스를 사용하라.

오픈 액세스가 가장 높은(즉 가장 덜 제한적인) 레벨의 액세스를 가지며, private 액세스가 가장 낮은(가장 제한적인) 액세스 레벨을 갖는다.

오픈 액세스는 클래스와 클래스 멤버에만 적용되며, 퍼블릭 액세스와의 차이점은 모듈 바깥의 코드가 서브클래싱이나 오버라이딩을 할 수 있게 해준다는 점이다. 클래스를 오픈으로 명시해준다는 것은 다시 말하자면 해당 클래스를 슈퍼클래스로 사용하는 다른 모듈들의 코드에 영향을 줄 수 있다는 점을 고려했다는 뜻이며, 이에 따라 클래스의 코드를 작성했다는 것을 의미한다.

 

1. 액세스 레벨의 가이딩 원칙

 

스위프트의 액세스 레벨은 전반적인 가이딩 원리를 따른다: 엔티티는 자신보다 더 낮은(더 제한적인) 액세스 레벨을 갖는 엔티티로는 정의할 수 없다.

예를 들면 다음과 같다.

 

  • 퍼블릭 변수는 internal, file-private, private 타입을 갖는 것으로 정의해줄 수 없다. 그 타입들은 해당 퍼블릭 변수가 사용되는 모든 곳에서 사용될 수는 없기 때문이다.
  • 함수는 자신의 매개변수나 리턴 타입보다 더 높은 액세스 레벨을 가질 수 없다. 함수의 구성요소들이 주변 코드에서 접근 불가능한 상황이 있을 수 있기 때문이다.

2. 디폴트 액세스 레벨

 

몇 가지 예외 사항을 빼고는 코드 내부의 모든 엔티티는 액세스 레벨을 명시해주지 않을 경우 internal이라는 디폴트 액세스 레벨을 갖는다. 따라서 보통 코드에서 액세스 레벨을 반드시 명시해줄 필요는 없다.

 

3. 싱글 타겟 앱의 액세스 레벨

 

간단한 싱글 타겟 앱을 만들 경우, 앱의 코드는 보통 앱 내부에서만 사용되고 해당 앱의 모듈 바깥에서 사용하도록 만들어줄 필요가 없다. internal이라는 디폴트 액세스 레벨만으로 이미 이 조건을 충족한다. 따라서 커스텀 액세스 레벨을 명시해줄 필요가 없다. 그러나 상황에 따라 해당 코드의 일부분을 file private이나 private으로 해줌으로써 앱의 모듈 내부의 다른 코드로부터 그 세부사항을 숨길 필요가 있는 경우도 있다.

 

4. 프레임워크의 액세스 레벨

 

프레임워크를 개발할 때 해당 프레임워크에서 공개되어야 할 인터페이스는 이를 임포트하는 앱 등 타 모듈에서 접근 가능하도록 open이나 public으로 명시하라. 이 public-facing 인터페이스는 해당 프레임워크의 application programming interface(API)가 된다.

 

5. 단위 테스트 타겟의 액세스 레벨

 

앱에 단위 테스트 타겟을 포함시킬 경우 앱 내부의 코드는 테스트되기 위해 해당 모듈에서 접근 가능해야 한다. open이나 public으로 명시된 엔티티만이 다른 모듈에서 접근 가능한 게 원칙이다. 그러나 유닛 테스트 타겟의 경우, @testable 애트리뷰트로 프로덕트 모듈에 대한 선언을 import하면 인터널 엔티티도 접근할 수 있고, 해당 프로덕트 모듈을 테스팅 가능한 상태로 컴파일할 수 있다.

 

6. 액세스 컨트롤 구문

 

open, public, internal, fileprivate, private 수식어를 엔티티의 선언 맨 앞에 적어줌으로써 엔티티의 액세스 레벨을 정의해줄 수 있다.

public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

따로 명시해주지 않을 경우 디폴트 액세스 레벨은 인터널이다. 따라서 위의 예시에서 SomeInternalClass와 someInternalConstant는 명시적인 access-level 수식어 없이 적어줄 수 있고, 그렇게 하더라도 똑같이 인터널 액세스 레벨을 갖는다.

class SomeInternalClass {}              // implicitly internal
let someInternalConstant = 0            // implicitly internal