[Swift] 접근 제어자 (Access Control)
접근 제어자란..?
코드를 작성하는 한 파일에서 다른 파일에 있는 코드에 대한 접근을 명시적으로 작성하여 이를 관리하는 것입니다.
이를 이용해 우리는 module과 source file에 따라 다른 접근을 할 수 있게 됩니다.
Module
하나의 프레임워크를 의미하여 코드 상에서 import 키워드로 추가되는 것들이 바로 module이다. 대표적으로 UIKit, Foundation 등이 module에 해당하며, 프로젝트 하위에 있는 각각의 target들도 하나의 module에 속합니다.
Source File
각 module 안에 있는 파일들을 말한다. 예를 들어, viewContoller.swift 같은 파일들이 하나의 source file에 해당됩니다.
Swift의 5가지 접근 제어자
특정 접근 제어자가 적용되는 대상을 entity라 하며, entity는 접근 제어자를 작성할 수 있는 class, struct, 프로퍼티, 메소드 등의 집합을 의미합니다.
open, public | 프로젝트 내 모든 module에서 해당 entity에 접근 가능 |
internal | default로 설정되는 접근 제어자. entity가 작성된 module에서만 접근 가능 |
fileprivate | entity가 작성된 source file에서만 접근 가능 |
예를 들어, 서로 다른 클래스가 같은 파일에 있고 fileprivate로 선언되어 있다면 두 클래스는 서로 접근할 수 있다. | |
private | 특정 객체에서만 사용할 수 있도록 제한하는 가장 제한적인 접근 제어자 |
서로 다른 두 클래스가 같은 파일 내에 있더라도 private으로 선언되어 있다면 둘은 서로 접근할 수 없다. |
open과 public의 차이
open은 다른 모듈에서 subClass가 가능하지만, public은 그렇지 않습니다.
open은 클래스에만 사용될 수 있으며, 한 모듈에서 만든 클래스를 superClass로 하는 subClass를 다른 모듈에서 만들기 위해서는 해당 superClass가 open으로 선언되어야 한다. 당연히 overriding도 이 규칙이 적용됩니다.
접근 제어자 관련 규칙
- 접근 제어자의 디폴트 값은 internal
- 상위 entity보다 더 제한적인 접근 제어자를 갖는 entity는 정의할 수 없다.
예시를 들어보겠습니다.
private struct Car {
public var engine: String // error
}
보면 Car는 private, 그 안의 engine은 public으로 정의되어 있는데, 이러한 접근 제어자 형태는 사용할 수 없습니다.
접근 제어자는 특정 entity로부터의 상대적인 기준이 적용되는 것이 아니라 전체 프로젝트를 기준으로 적용되기 때문입니다.
따라서 특정 entity 안의 변수나 메소드들은 해당 entity의 접근 제어자보다 강하게만 적용될 수 있고 더 약하게 적용될 수는 없습니다.
유용한 기타 사항
Unit Test에서는 @testable 키워드로 모듈을 import하여 public과 open이 아닌 entity도 사용할 수 있습니다.
@testable import [module_name]
특정 Unit Test 파일의 상단에 위와 같이 선언해주면, 해당 모듈의 entity를 internal 형태로 사용할 수 있게 된다.
Getter와 Setter에서 서로 다른 접근 제어자를 적용할 수 있습니다.
Swift에서는 setter를 getter보다 더 제한적으로 설정할 수 있습니다. (그 반대는 불가능)
private(set) var name: String
예를 들어 위와 같이 적용할 경우, getter는 internal이 되고 setter는 private이 됩니다.
protocol에서 선언된 변수의 접근제어자는 조건을 만족한 경우에만 사용할 수 있다. 여러가지 예시 중 private(set)과 관련된 예시를 살펴봅시다.
protocol Car {
//
}
struct CarModel: Car {
private(set) var engine: String
}
위 예시에서 Car protocol의 빈 영역에 어떤 접근제어자가 들어가야 할까요?
→ private(set)은 외부에서 settable 하지 않기 때문에 프로토콜에는 gettable만 들어가게 된다.
protocol Car {
var engine: String { get }
}
struct CarModel: Car {
private(set) var engine: String
}
이 외 예시는 https://stackoverflow.com/questions/30573872/swift-protocol-get-only-settable/38281420#38281420를 참고하면 좋을거 같습니다.
Swift Protocol get only settable?
why can I do this without any error: var testDto = ModelDto(modelId: 1) testDto.objectId = 2 while I define this: protocol DataTransferObject { var objectType: DtoType { get } var
stackoverflow.com
출처
Swift 접근 제어자(Access Control)
Swift의 접근제어자에 대해 간단히 정리했습니다.
hcn1519.github.io
오늘도 화이팅입니다!