접근 제한자는 다른 소스 파일이나 모듈의 코드에서 코드 일부에 대한 액세스를 제한한다.
이 기능은 코드의 세부 구현 사항을 숨기고, 해당 코드를 접근하고 사용할 수 있는 기본 인터페이스를 지정할 수 있게 한다.
코드의 세부 구현 사항을 숨기기때문에 객체 지향의 은닉화
가 가능해진다.
💡 은닉화란?
객체 외부에서 객체 내의 자료의 접근을 제한하고 데이터를 수정, 조작하는 동작은 내부에 두고 접근(getter), 설정(setter)하는 메소드로 결과만 받는것이다.
외부에서는 내부의 움직임을 알 수가 없으며 데이터에 어떤 값이 있는지, 어떤 변화가 일어나는지 알 수 없으며 단지 데이터의 접근을 메서드(setter, getter)를 통해 결과만 받을뿐이다.
한마디로, 다른 소스파일 및 모듈의 코드에서 코드 일부에 대해서 못 보게 막아버리는 것이다. 접근 지정자는 은닉화를 가능하게 해줘서, 다른 사용자들이 딱 사용해야하는 정보만 볼 수 있도록 해준다.
접근 제한자는 클래스
, 구조체
, 열거형
같은 개별 타입뿐만 아니라 해당 타입에 속하는 프로퍼티
, 메소드
, 이니셜라이저
에 사용 가능하다.
프로토콜
은 전역 상수, 변수, 함수처럼 특정 컨텍스트로 제한될 수 있다.
모듈
: 하나의 코드 묶음 (하나의 프레임워크, 하나의 라이브러리, 하나의 애플리케이션)
swift의 import키워드를 사용하여 다른 모듈에서 가져올 수 있는 framework 또는 응용 프로그램같은 라이브러리들이 모두 모듈이다.
소스파일
: .swift파일 하나의 단위
엔티티를 정의한 모듈의 모든 소스 파일 내뿐만 아니라 정의한 모듈을 가져다 쓰는 다른 모듈의 소스파일에서도 사용
할 수 있다. 일반적으로 framework에 공용 인터페이스를 지정할 때 public, open 접근을 사용한다.
public보다 더 개방적인 접근수준을 지정한다. class와 class 멤버에만 사용될 수 있다.
모듈 밖에서도
클래스를 상속할 수 있고, 클래스의 멤버를 서브클래싱이나 override 할 수 있다. 명시적으로 open으로 표시하면 해당 클래스를 super class로 사용하는 다른 모듈의 코드의 영향을 고려하면서 코드를 짤 수 있다.
어디서든 사용될 수 있는 접근수준을 지정한다.
정의된 모듈 내에서만 서브클래싱이나 override 가능하다.
외부 상속은 불가능하다. (open을 제외한 모든 접근이 동일하다.)
엔티티가 정의된 모듈의 모든 소스 파일 내에서 상속, 재정의, 사용할 수 있지만, 외부의 소스파일에서는 접근할 수 없다. 정의된 모듈 안에서만 사용 가능
일반적으로 app이나 framework의 내부 구조를 정의할 때 internal 접근을 사용한다.
아무런 접근 제한자가 선언되지 않았다면 기본적으로 모든 요소에 암묵적으로 지정되는 접근수준인 internal 접근 수준을 가지게 된다.
fileprivate 접근을 사용하면 해당 세부 정보가 전체 파일 내에서 사용될 때 특정 기능의 구현 세부 정보를 숨길 수 있습니다. private 접근은 단일 정의 내에서만 사용되는 특정 기능 조각의 구현 상세 내역을 숨길 수 있습니다.
같은 파일 내
의 다른 위치에서 상속, 재정의, 사용이 가능하고 다른 파일에서는 접근할 수 없다.
swift는 하나의 .swift 파일 안에 여러 개의 타입을 선언할 수 있는 특성을 가지고 있다. fileprivate은 이러한 파일 스코프를 활용하여 특정 기능의 세부 구현을 파일 내에서만 공유하고 전체 파일 내에서 특정 기능의 세부 구현 정보를 숨기고자 할 때 사용한다.
같은 스코프 안에서만 액세스
할 수 있다.
같은 클래스나 구조체 내에서만 사용할 수 있으며, 외부에서는 접근할 수 없습니다. 해당 타입의 내부 상태나 구현의 일부를 외부로부터 숨기고자 할 때 유용하다. 정보 은닉의 관점에서 중요한 역할을 한다.
swift4 이후부터 같은 소스파일 안에서의 extension에도 private를 사용할 수 있다.
(제약 적음) open > public > internal > filePrivate > private (제약 많음)
모든 타입에 적용되는 접근지정자 규칙은 상위 요소보다 하위 요소가 더 높은 접근수준을 가질 수 없다.
예를 들면 private으로 선언된 클래스에서 public 프로퍼티나 함수를 가질 수 없고, 매개변수나 반환값은 함수의 접근지정자보다 같거나 높아야 하고,
열거형의 원시 값의 타입은 열거형 자체의 접근수준보다 높아야 한다.
주로 라이브러리나 프레임워크와 같이 외부에서 사용되는 모듈을 만들 때 사용한다. 보통 앱을 만들때는 작성한 소스코드가 외부에서 사용될 일이 없기 때문에 굳이 사용할 필요가 없다.
프로젝트를 만들 때 접근 제한자를 명시해가며 소스코드를 작성할 필요는 없지만 앱 자체적으로 구현 세부 정보를 다른 코드로부터 숨기려면 fileprivate
이나 private
를 사용하면 된다.
그리고 어플리케이션이나 작은 프로젝트의 경우, 명시적인 접근 제한자를 사용하지 않더라도 swift에서 기본으로 제공되는 기본 접근 수준이 충분히 잘 동작할 수 있다. 단일 타겟 앱에서는 명시적인 접근 제한자를 사용할 필요성이 적다.
// ModuleA.swift
// open 접근 수준, 모듈 외부에서도 상속 가능하도록 지정
open class BaseClass {
// open 접근 수준
open func publicMethod() {
print("This is a public method")
}
// internal 접근 수준
internal var internalProperty = 10
// fileprivate 접근 수준
fileprivate func fileprivateMethod() {
print("This is a fileprivate method")
}
// private 접근 수준
private var privateProperty = "private property"
// private 접근 수준
private func privateMethod() {
print("This is a private method")
}
// BaseClass 내부에서만 접근 가능한 중첩된 클래스
private class NestedClass {
func nestedMethod() {
print("This is a nested method")
}
}
}
// ModuleB.swift
import ModuleA
// ModuleB에서 ModuleA의 BaseClass를 상속한 DerivedClass 정의, public 접근 수준
public class DerivedClass: BaseClass {
// public 접근 수준
public func someMethod() {
print("This is a public method in DerivedClass")
}
// Private 접근 수준
private func privateMethodInDerivedClass() {
print("This is a private method in DerivedClass")
}
}
// Main.swift
import ModuleA
let baseObject = BaseClass()
baseObject.publicMethod() // Public 접근 수준
print(baseObject.internalProperty) // internal 접근 수준
baseObject.fileprivateMethod() // fileprivate 접근 수준
// baseObject.privateProperty // 접근 불가능: 'privateProperty' is inaccessible due to 'private' protection level
// baseObject.privateMethod() // 접근 불가능: 'privateMethod()' is inaccessible due to 'private' protection level
// let nestedObject = BaseClass.NestedClass() // 접근 불가능: 'NestedClass' is inaccessible due to 'private' protection level
let derivedObject = DerivedClass()
derivedObject.someMethod() // Public 접근 수준
// derivedObject.privateMethodInDerivedClass() // 접근 불가능: 'privateMethodInDerivedClass()' is inaccessible due to 'private' protection level