사용자 정의 타입(custom types)
- 사용자 정의 타입에 명시적 접근 수준을 지정하고 싶다면, 타입 정의 간 지정한다. 그러면 새로운 타입의 접근 수준이 허용하는 범위 내 해당 타입을 사용 가능하다. 예를 들어서 file-private클래스를 정의하면 해당 클래스는 file-private클래스가 정의된 소스파일에 프로퍼티 타입 또는 함수의 파라미터, 반환타입으로만 사용될 수 있다.
- 타입의 접근 수준은 해당 타입의 멤버(프로퍼티, 메서드, 초기화 구문, 서브 스크립트)의 기본 접근 수준에도 영향을 미친다. 타입의 접근 수준을 private으로 정의하면 멤버들의 기본 접근 수준도 private이 된다.
public class SomePublicClass {
public var somePublicProperty = 0
var someInternalProperty = 0
fileprivate func someFilePrivateMethod() {}
private func somePrivateMethod() {}
}
class SomeInternalClass {
var someProperty = 0
fileprivate func someFilePrivateMethod() {}
}
fileprivate class someFilePrivateClass {
var someProperty = 0
private func someFilePrivateMethod() {}
}
튜플 타입(Tuple)
- 튜플 타입에 대한 접근 수준은 해당 튜플에서 사용되는 모든 타입에 가장 제한적 접근 수준이다. 하나는 internal, 하나는 private이라면, 전체적 접근 수준은 private이다.
- 튜플은 클래스, 구조체, 열거형, 함수와 같이 독립형 정의가 없으므로 이 접근 수준은 튜플 타입을 구성하는 타입에서 자동으로 결정되고 명시적으로 지정 가능하다.
함수 타입(Function)
- 함수 타입에 대한 접근 수준은 함수의 파라미터 타입과 반환 타입 중 가장 제한적 접근 수준으로 계산된다. 파라미터 타입이 internal, 반환 타입이 private이라면 이는 private수준을 가진다. 파라미터가 더 폐쇄적이고 반환타입이 개방적인 경우도 마찬가지로 적용된다.
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
}
열거형 타입(Enumeration)
- 열거형이 가지는 각 케이스들은 열거형과 같은 수준을 자동으로 물려받는다. 또한 개별 열거형 케이스에 대한 접근 수준을 지정할 수 없다.
public enum CompassPoint {
case north
case south
case east
case west
}
- 원시값(rawvalue)과 연관된 값(associated value)타입은 열거형 접근 수준보다 높은 수준이어야 한다. internal접근 수준의 열거형 원시값 타입으로 private을 사용할 수 없다.
반면 public은 사용이 가능하다.
중첩된 타입(Nested type)
- 중첩된 타입의 접근 수준은 포함한 타입이 public이 아닌 경우 포함한 타입과 동일하다. public타입 내의 중첩된 타입은 자동으로 internal을 가지게 된다.
- public접근 수준을 가진 타입 내 중첩된 타입이 internal이 아닌 public 접근 수준을 가지려면, 명시적으로 public으로 중첩된 타입을 선언해주어야 한다.
서브클래싱(Subclassing)
- 하위 클래스는 상위 클래스보다 더 높은 접근 수준을 가질 수 없다. 예를 들어서 internal상위 클래스에 public 하위 클래스를 작성할 수 없다.
- 하위클래스가 상위클래스를 상속할 때 접근 수준을 재정의(overriding) 해줄 수 있다.
public class A {
fileprivate func someMethod() {
}
}
internal class B : A {
override internal func someMethod() {
}
}
public class A {
fileprivate func someMethod() {
}
}
internal class B : A {
override internal func someMethod() {
super.someMethod()
}
}
상수, 변수, 프로퍼티 및 서브 스크립트
- 상수, 변수 또는 프로퍼티는 타입보다 더 열린 접근 수준을 가질 수 없다. private타입 안에서 public 프로퍼티를 작성할 수 없다.
- 이들은 private타입을 사용시 명시적으로 표시해주어야 한다.
private var privateInstance = SomePrivateClass()
Getter와 Setter
- 위의 프로퍼티 감시자는 속해있는 상수, 변수, 프로퍼티 및 서브스크립트에 대한 접근 수준을 인수한다.
- 해당 읽기 및 쓰기 범위를 제한하기 위해서 getter보다 낮은 접근 수준으로 setter 제공이 가능하다. var전에 private(set), fileprivate(set)등의 키워드를 통해서 더 낮은 접근 수준을 할당한다.
struct TrackedString {
private(set) var numberOfEdits = 0
var value : String = "" {
didSet {
numberOfEdits += 1
}
}
}
초기화 구문(initializer)
- 사용자 정의 초기화 구문은 초기화 하는 타입보다 더 낮거나 같은 수준으로 할당이 가능하다. 유일한 예외는 필수 초기화 구문이다. 필수 초기화 구문은 자신이 속한 클래스와 동일한 접근 수준을 가져야 한다.
- 기본 초기화 구문은 타입이 public으로 정의 되지 않는 이상 초기화 하는 타입과 같은 접근 수준을 가진다.
- 구조체의 모든 저장된 프로퍼티가 private이라면 구조체 타입의 기본 멤버별 초기화 구문은 private이라고 간주한다. 마찬가지로 저장된 프로퍼티가 fileprivate이라면 fileprivate을 가진다고 간주한다. 위 기본 초기화 구문과 마찾가지로, Public 구조체 타입은 타입의 정의 부분으로 public멤버별 초기화 구문을 자체적으로 제공해야 한다.
프로토콜(Protocol)
- 프로토콜 타입에 명시적 접근 수준을 할당하려면 프로토콜 정의 시점에서 지정하면 된다.
- 프로토콜 정의 내 각 요구사항의 접근 수준은 자동으로 프로토콜과 같은 수준으로 지정된다.
- 타입과 다르게, public 프로토콜을 정의하면 요구사항은 구현이 전부 public수준을 요구한다. 이는 타입이 public이더라도 명시적이지 않은 경우는 internal로 설정되는 것과 차이가 있다.
- 프로토콜을 상속하는 새로운 프로토콜은 상속받은 프로토콜과 최대 동일한 접근 수준을 가질 수 있다. internal프로토콜을 상속하면 public을 작성 불가하다.
확장(extension)
- 확장에 추가된 모든 타입의 멤버는 기존 타입에 선언된 타입의 멤버와 같인 기본 접근수준을 가진다. public 또는 internal 타입으로 확장하면 추가한 모든 타입 멤버는 internal을 가진다.
- 확장 내에서 정의된 모든 멤버에 대해 새로운 접근 수준을 할당하기 위해서 private과 같이 명시적으로 접근 수준 수식어를 줄 수 있다. 또한 확장 내에서 개별 타입 멤버를 다시 정의하는 것도 가능하다.
제네릭(generic)과 타입 별칭
- 제네릭 타입 또는 함수에 대한 접근 수준은 제네릭 타입 또는 함수 자체의 접근 수준과 해당 타입 파라미터에 대한 모든 타입의 제약조건의 최소 수준이다.
- 타입 별칭은 별칭이 지정된 타입의 접근수준보다 작거나 같은 수준을 가질 수 있다. 이는 프로토콜의 타입별칭 또한 마찬가지 이다.