Access Control
- 접근 제어
- 다른 소스 파일 및 모듈의 코드에서 코드의 일부에 대한 접근을 제한하는 것 (불필요한 접근 방지)
- 개별 타입 (class, struct, enum) 뿐 만 아니라 해당 타입에 속하는 프로퍼티, 메소드, 이니셜라이저 및 첨자 (subscripts) 에 대해 특정 접근 레벨을 지정할 수 있다.
- 프로토콜은 전역 상수, 변수 및 함수처럼 특정 컨텍스트로 제한될 수 있다.
- Swift 는 코드 내의 개체에 대해 5가지 접근 레벨 (open / public / internal / fileprivate / private) 을 제공한다.
- open -> public -> internal -> fileprivate -> private 순으로 더 범위가 제한적이다.
Module
- 코드의 묶음 단위
- 프레임워크, 라이브러리, 어플리케이션처럼 배포할 코드들의 묶음
- ex. App Bundle, Framework
Source File
- 모듈 내의 단일 Swift 소스 코드 파일
- ex. ViewController.swift
은닉화
- 객체 외부에서 객체 내의 자료에 접근하는 것을 제한하는 것
- 데이터를 수정 / 조작하는 동작은 내부에 두고, 접근 (getter) / 설정 (setter) 하는 메소드로 결과만 받는 것
- 외부에서는 내부적인 움직임을 알 수 없고, 데이터에 어떤 값이 있는지 또는 어떤 변화가 일어나는지 알 수 없다.
- 단지 데이터의 접근을 메소드 (getter, setter) 를 통해서 결과만 받을 뿐이다.
Open
- 가장 제한이 적은 접근 레벨
- 모듈 외부에서도 접근이 가능하다. (개방 접근 수준)
- 클래스와 클래스 멤버에만 붙일 수 있다.
- 모듈 밖의 다른 모듈에서 상속될 수 있다.
- open 으로 선언된 클래스의 멤버 (프로퍼티, 메소드) 들만이 다른 모듈에서 override 될 수 있다. (ex. UIKit 에 있는 UIViewController 의 정의를 보면 open 클래스로 되어있는 것을 볼 수 있는데, UIViewController 가 open 클래스이기 때문에 어떠한 클래스가 UIViewController 클래스를 상속받으면 viewDidLoad 함수 등을 override 할 수 있는 것이다.)
Public
- 모듈 외부에서도 접근이 가능하다. (공개 접근 수준)
- 'open' 과 다르게 해당 클래스를 상속해도 해당 클래스의 멤버들을 override 할 수 없다. (만약에 UIViewController 가 public 클래스로 되어있었다면, UIViewController 클래스를 어떠한 클래스에서 상속받아도 viewDidLoad 함수 등을 override 할 수 없다.)
Internal
- 하나의 모듈 내부에서만 접근이 가능하다. (내부 접근 수준)
- 따로 접근 제어자를 붙여주지 않으면 자동으로 붙는 기본 접근 제어자 (굳이 작성할 필요없다.)
- 같은 모듈 내에서는 어디서든 접근 가능하고, 클래스의 경우에는 어느 곳에서도 해당 클래스를 상속받을 수 있다.
Fileprivate
- 하나의 스위프트 파일 (.swift) 내에서만 접근이 가능하다. (파일 내부 접근 수준)
- 다른 언어에서는 하나의 파일에 하나의 클래스 혹은 하나의 타입만 정의하지만, 스위프트에서는 종종 관련이 있기만 하면 같은 파일에 여러 타입을 정의하기도 하기 때문에 필요하다.
- 해당 소스 파일 외부에서 값이 변경되거나 함수를 호출했을 때 부작용이 생길 수 있는 경우에 사용하면 좋다.
Private
- 가장 제한이 많은 접근 레벨 (비공개 접근 수준)
- 정의한 블록 내부에서만 접근이 가능하다.
- 개체의 사용을 enclosing 선언과 동일한 파일에 있는 해당 선언의 extension (Swift 3 에서는 불가능했는데, Swift 4 부터는 가능하다.) 으로 제한한다.
- 단일 정의 내에서만 사용되는 특정 기능 조각의 구현 상세 내역을 숨길 수 있다.
class MyName {
private var name = "r1verfuture"
}
class Test {
func getMyName() {
private let myNameInstance = MyName()
print(myNameInstance.name)
}
}
- [코드 1] 을 실행하면 에러가 나는데, 그 이유는 Test 클래스에서 MyName 클래스의 private 변수인 'name' 에 접근하려고 했기 때문이다.
class MyName {
private var name = "r1verfuture"
}
extension MyName {
func getMyName() {
print(name)
}
}
- [코드 2] : 같은 소스 파일 내에서 해당 클래스를 extension 한 내부에 private 변수 접근 코드를 써도 에러가 나지 않는다.
- 하지만, 무조건 같은 소스 파일 내에서만 가능하다.
접근 제어자를 사용할 때 주의해야할 것
- 상위 요소의 접근 제어 수준보다 높은 수준의 하위 요소는 있을 수 없다. ([코드 3] 참고)
- 함수의 매개변수로 특정 접근 수준이 부여된 타입이 전달되거나 반환된다면, 그 타입의 접근 수준보다 함수의 접근 수준이 높게 설정될 수 없다. ([코드 4] 참고)
- 프레임워크를 만들 때는 다른 모듈에서 특정 기능에 접근할 수 있도록 공개 접근 수준으로 지정해주어야 한다.
- 열거형 (enum) 내부의 각 case 별로 따로 접근 수준을 부여할 수 없고, 각 case 의 접근 수준은 열거형 자체의 접근 수준을 따른다.
private class AClass {
public func aFunc() { }
}
public func aFunc(aClass: AClass) -> AClass {
return a
}
참고