접근 제한자는 다른 소스 파일이나 모듈의 코드에서 코드 일부에 대한 액세스를 제한해요.
이 기능은 우리 코드의 세부 구현 사항을 숨기고, 해당 코드를 접근하고 사용할 수 있는 기본 인터페이스를 지정할 수 있게 합니다.
우리 코드의 세부 구현 사항을 숨기기 때문에 객체 지향의 은닉화를 가능하게 해줘요!
Swift는 모듈과 소스파일 기반으로 접근 제한자가 설계되어 있어요.
그럼 그 모듈과 소스파일이 뭔지 알아야겠죠?
모듈
모듈은 하나의 코드 묶음이에요.
하나의 프레임워크, 하나의 라이브러리, 하나의 애플리케이션이 모듈의 단위입니다.
더 간단하게 말하자면, Swift의 import키워드를 사용하여 다른 모듈에서 가져올 수 있는 framework 또는 응용 프로그램을 생각하면 됩니다.
우리가 import해서 사용하는 라이브러리들이 모두 모듈인거죠.
소스파일
소스파일은 모듈보다 쉽게 이해할 수 있어요.
소스파일은 .swift파일 하나의 단위입니다.
앱 또는 framework내의 단일 파일인 swift 소스 코드 파일을 생각하시면 됩니다.
The Swift Programming Language에 따르면 은닉화는 이런 의미를 가지고 있어요.
객체 외부에서 객체내의 자료로의 접근을 제한하고 데이터를 수정, 조작하는 동작은 내부에 두고 접근(getter), 설정(setter)하는 메소드로 결과만 받는것이다. 외부에서는 내부적인 움직임을 알 수가 없으며 데이터에 어떤 값이 있는지 또는 어떤 변화가 일어나는지 알 수 없으며 단지 데이터의 접근을 메서드(setter, getter)를 통해 결과만 받을뿐이다.
한마디로, 다른 소스파일 및 모듈의 코드에서 코드 일부에 대해서 못 보게 막아버리는 걸 은닉화라고 부르는거죠.
접근 지정자는 은닉화를 가능하게 해줘서, 다른 사용자들이 딱 사용해야하는 정보만 볼 수 있도록 해줘요.
접근 제한자는 클래스(Class), 구조체(Struct) 및 열거(Enum)와 같은 개별 타입뿐만 아니라, 해당 타입에 속하는 프로퍼티, 메소드, 이니셜라이저에 사용 가능합니다.
프로토콜의 경우에는 전역 상수, 변수 및 함수처럼 특정 컨텍스트로 제한될 수 있어요.
public, open 접근을 사용하면, 엔티티를 정의한 모듈의 모든 소스 파일 내뿐만 아니라 정의한 모듈을 가져다 쓰는 다른 모듈의 소스파일에서도 사용할 수 있습니다. 일반적으로 framework에 공용 인터페이스를 지정할 때 public, open 접근을 사용합니다.
public
어디서든 사용될 수 있는 접근수준을 지정해요.
외부 상속이 불가능하고, class 멤버를 override할 수 없어요.
정의된 모듈 내에서만 서브 클래싱이 가능해요.(open를 제외한 모든 접근이 동일해요)
class, class 멤버는 정의된 모듈 내에서만 서브클래싱이나 override가 잘 돼요.
framework 내부에서만 서브클래싱이 가능해요.
open
public보다 더욱 개방적인 접근수준을 가져요.
class와 class 멤버에만 사용될 수 있어요.
모듈 밖에서 클래스를 상속될 수 있도록 만들고, 클래스의 멤버를 모듈 밖에서 재정의 할 수 있도록 만들어요.
어디서든 서브클래싱이 가능해요.
class, class 멤버는 정의된 모듈 내에서나, 그 모듈을 import하는 외부 모듈에서나 서브클래싱이나 override가 잘 돼요.
framework 내부, framework 외부 어디서든 서브클래싱이 가능해요.
클래스는 open으로 사용할 수 있기에, 명시적으로 open으로 표시하면 해당 클래스를 super class로 사용하는 다른 모듈에서 가져온 코드의 영향을 고려했으므로, 클래스 코드를 적절하게 디자인했음을 나타내요.
internal 접근은 엔티티가 정의된 모듈의 모든 소스 파일 내에서 사용되지만, 해당 모듈 외부의 소스파일에서는 사용되지 않도록 합니다. 일반적으로 app이나 framework의 내부 구조를 정의할 때 internal 접근을 사용합니다.
internal은 기본적으로 모든 요소에 암묵적으로 지정되는 접근수준이라서 아무런 접근 제한자가 선언되지 않았다면 internal 접근 수준을 가지게 돼요.
internal은 같은 모듈 내에서 상속, 재정의, 사용까지 가능해요. 하지만 모듈 외부는 접근이 불가능합니다.
즉, internal은 오직 정의된 모듈 안에서만 사용하자! 라는 의미를 지닌 접근 제한자예요.
fileprivate 접근을 사용하면 해당 세부 정보가 전체 파일 내에서 사용될 때 특정 기능의 구현 세부 정보를 숨길 수 있습니다. private 접근은 단일 정의 내에서만 사용되는 특정 기능 조각의 구현 상세 내역을 숨길 수 있습니다.
fileprivate
같은 파일 안에서는 엑세스 가능해요.
같은 소스코드 안에서 상속, 재정의, 사용이 가능하도록 만들어요.
.swift 파일 안에서 여러 타입을 선언할 수 있는 swift언어의 특성을 고려한 접근 제한자예요.
전체 파일 내에서 특정 기능의 세부 구현 정보를 숨기고자 할 때 사용해요.
private
같은 스코프 안에서만 액세스 가능해요.
같은 타입안에서만 사용 가능하며 그 외의 어떠한 상황에서도 접근 불가능해요.
같은 타입 안에서 상태나 정보를 은닉화시킬 때 사용해요.
swift4 이후부터는 같은 소스파일안에서의 extension에서도 private를 사용할 수 있어요.
private class PrivateClass{
public init() {}
private var name = "HI"
}
extension PrivateClass{
func someMethod(){
print(name)//OK
}
}
완벽한 객체지향을 추구한다면 private를 쓰고 getter, setter를 이용하는 게 좋아요.
(제약 적음) open < public < internal < fileprivate < private (제약 많음)
모든 타입에 적용되는 접근지정자 규칙은 "상위 요소보다 하위 요소가 더 높은 접근수준을 가질 수 없다." 입니다.
예를 들자면,
private으로 선언된 클래스에서 public 프로퍼티나 함수를 가질 수 없고,
매개변수나 반환값은 함수의 접근지정자보다 같거나 높아야 하고,
열거형의 원시 값의 타입은 열거형 자체의 접근수준보다 높아야 합니다.
주로 라이브러리나 프레임워크를 만들 때 사용합니다.
왜냐면 라이브러리와 프레임워크는 외부에서 사용되는 모듈이니깐요.
우리가 보통 앱을 만들때는 굳이 사용할 필요가 없습니다.
왜냐면 우리가 작성한 소스코드 자체가 외부에서 사용될 일이 없으니까요!
우리가 특별히 접근 제한자를 명시해가며 소스코드를 작성할 필요가 없다만 앱 자체적으로 구현 세부 정보를 다른 코드로부터 숨기려면 fileprivate이나 private를 사용하면 됩니다.
swift는 다양한 수준의 접근 제어 외에도 일반적인 시나리오에 대한 기본 접근 수준을 제공함으로써, 명시적 접근 제어 수준을 지정할 필요성을 줄여줍니다. 따라서 단일 타겟 app를 만드는 경우에는 명시적 접근 제한자를 지정하지 않아도 됩니다.