접근 제어자
생각보다 접근 제어자를 설명하기에 많은 내용이 필요한것 같아 정리해봅니다.
다양한 예제를 포함해서 정리해보겠습니다.
Swift의 접근제어자는 단계별로 5개의 단계가 있습니다.
하나씩 정리해보자면
open
- 모듈 외부에서 접근 가능합니다.
- open만이 다른 모듈에서 상속/재정의가 가능합니다.
- 상속 재정의가 가능하므로 클래스에서만 사용가능합니다.
- 만약 구조체에서 open을 사용시 에러가 발생합니다.
public
- 모듈 외부에서 접근 가능
- 클래스를 public으로 선언한다면 상속, 재정의가 불가능합니다.
internal
- 접근제어자를 설정해주지 않으면 default로 설정되는 접근제어자입니다.
- 같은 모듈 내에서 어디서든 접근 가능합니다.
- 같은 모듈 내에서 상속/재정의가 가능합니다.
fileprivate
- 하나의 .swift파일 내에서만 접근이 가능합니다.
private
- 요소가 선언된 블럭 내에서만 접근 가능합니다.
- private(set)은 요소가 선언된 블록 내에서만 수정이 가능합니다. 외부에서는 조회가 불가능합니다.
private(set)을 더욱 잘 이해하기 위한 예시입니다.
class Counter {
private(set) var count = 0
func increment() {
count += 1
}
let myCounter = Counter()
mycounter.count // 0
mycounter.increment()
mycounter.count // 1
mycounter.count = 2 // 에러가 발생합니다
// count의 set이 private이기 때문에 count의 set은 선언된 블럭 내부에서만 가능합니다.
참고로 set만 private으로 설정이 되었으므로 get은 설정해주지 않았으니 Internal이 됩니다.
만약 아래처럼 정의할 경우
public class Counter {
public private(set) var count = 0
}
이런 경우 get속성은 public이 됩니다.
접근 제어자 원칙
접근 제어자를 사용할 경우 지켜야할 원칙이 있습니다.
1. 바깥 수준의 접근제어자보다 높은 수준의 내부요소는 존재할 수 없다.
internal class A {
public var count = 0
}
A클래스의 접근제어자는 internal인데 내부요소가 public이 될 순 없습니다. 최소한 같거나 낮은 접근제어자가 되어야합니다.
2. 특정 접근 제어 수준의 타입이 함수의 매개변수나 리턴타입이 되는 경우 해당 값의 접근제어자보다 높을 수 없습니다.
private class Test {}
public class MyClass {
public func someFunction(a: Test) -> Test {
return a
}
}
이 설명이 조금 어려울 수 있습니다. 예제로 보는게.. 아무래도
이 예제에서 Test클래스는 private입니다.
MyClass 내부의 someFunction함수는 private의 Test를 파라미터, 리턴타입으로 사용합니다.
someFunction는 public이므로 다른파일, 모듈 에서 사용 가능합니다.
그러므로 Test의 private제약에 위배되므로 컴파일러는 오류를 발생시킵니다.
3. 상속관계
1) 상속해서 만든 하위클래스는 상위클래스보다 더 높은 수준을 설정할 수 없다.
2) 동일 모듈에서 정의한 클래스의 상위멤버에 접근 가능하면 접근 수준을 올려서 재정의가 가능합니다.
이것도 예제가 빠를듯 합니다.
public class SuperClass {
private func privateMethod() {
print("private method in SuperClass")
}
internal func internalMethod() {
print("internal method in SuperClass")
}
}
public class SubClass: SuperClass {
// override func privateMethod() ==> private은 상속시 접근할 수 없으므로 불가능
public override func internalMethod() { // internal은 동일 모듈 내 접근 가능하므로 접근 수준을 올려서
print("internal Method in SubClass") // public으로 재정의가 가능
}
}
4. Extension
본체의 타입과 동일한 접근 수준을 유지합니다.
5. 내부 멤버가 명시적 선언을 하지 않는다면 default 접근제어를 따릅니다.
open class MyClass {
var some = "clamp"
}
타입의 접근 수준이 높다고 내부멤버의 접근 수준이 높아지지 않습니다.
고로 some은 internal이 되게 됩니다.
생각보다 접근제어자를 설명하기 위한 원칙이 많고 이를 쉽게 정리하기 위해 필요한 예제가 많아서 정리해봤습니다.