Swift:: 접근 제어

jahlee·2023년 5월 1일
0

Swift기초

목록 보기
26/26
post-thumbnail

모듈과 소스파일

스위프트의 접근제어는 모듈과 소스파일을 기반으로 설계되었다.

모듈

모듈(Module)은 배포할 코드의 묶음 단위이다. 통상 하나의 프레임워크(Framework)나 라이브러리(Library) 또는 애플리케이션(Application)이 모듈 단위가 될 수 있다. 스위프트에서는 import 키워드를 사용해 불러온다.

소스파일

소스파일은 하나의 스위프트 소스 코드 파일을 의미힌다. 자바나 Objective-C와 같은 기존 의 프로그래밍 언어에서는 통상 파일 하나에 타입을 하나만 정의한다. 스위프트에서도 보통 파일 하나에 타입 하나만 정의하지만, 때로는 소스파일 하나에 여러 타입(여러 개의 클래스나 구조체, 열거형 등)이나 함수 등 많은 것을 정의하거나 구현할 수도 있다.

접근수준

접근제어는 접근수준(Access Level) 키워드를 통해 구현할 수 있다.
각 타입(클래스, 구조체, 열 거형 등)에 특정 접근수준을 지정할 수 있고, 타입 내부의 프로퍼티, 메서드, 이니셜라이저, 서브스크립트 각각에도 접근수준을 지정할 수 있다.
접근수준을 명시할 수 있는 키워드는 open, public, internal, fileprivate, private 다섯 가지가 있다.
스위프트의 접근수준은 기본적으로 모듈과 소스파일에 따라 구분합니다.

접근수준키워드범위비고
개방 접근수준open모듈 외부까지클래스에서만 사용
공개 접근수준public모듈 외부까지-
내부 접근수준internal모듈 내부-
파일외부비공개 접근수준fileprivate파일 내부-
비공개 접근수준private기능정의 내부-

공개 접근수준 – public

public 키워드로 접근수준이 지정된 요소는 어디서든 쓰일 수 있다. 자신이 구현된 소스 파일은 물론, 그 소스파일이 속해 있는 모듈, 그 모듈을 가져다 쓰는 모듈 등 모든 곳에서 사용할 수 있다. 공개(Public) 접근수준은 주로 프레임워크에서 외부와 연결될 인터페이스를 구현하는데 많이 쓰인다. 우리가 사용하는 스위프트의 기본 요소는 모두 공개 접근수준으로 구현 되어 있다고 생각하면 된다.

개방 접근수준 – open

open 키워드로 지정할 수 있는 개방(Open) 접근수준은 공개(Public) 접근수준 이상으로 높은 접근수준이며, 클래스와 클래스의 멤버에서만 사용할 수 있다.
기본적으로 공개 접근수준과 비슷하지만 다음과 같은 차이점이 있다.

  • 개방 접근수준을 제외한 다른 모든 접근수준의 클래스는 그 클래스가 정의된 모듈 안에서만 상속할 수 있다.
  • 개방 접근수준을 제외한 다른 모든 접근수준의 클래스 멤버는 해당 멤버가 정의된 모듈 안에서만 재정의할 수 있다.
  • 개방 접근수준의 클래스는 그 클래스가 정의된 모듈 밖의 다른 모듈에서도 상속할 수 있다.
  • 개방 접근수준의 클래스 멤버는 해당 멤버가 정의된 모듈 밖의 다른 모듈에서도 재정의(override)할 수 있다.
  • 클래스를 개방 접근수준으로 명시하는 것은 그 클래스를 다른 모듈에서도 부모클래스로 사용 하겠다는 목적으로 클래스를 설계하고 코드를 작성했음을 의미한다.

내부 접근수준 – internal

internal 키워드로 지정하는 내부(Internal) 접근수준은 기본적으로 모든 요소에 암묵적으로 지정하는 기본 접근수준이다. 내부 접근수준으로 지정된 요소는 소스파일이 속해 있는 모듈 어디에서든 쓰일 수 있다. 다만 그 모듈을 가져다 쓰는 외부 모듈에서는 접근할 수 없다. 보통 외부에서 사용할 클래스나 구조체가 아니며, 모듈 내부에서 광역적으로 사용할 경우 내부 접근수준을 지정한다.

파일외부비공개 접근수준 – fileprivate

파일외부비공개(File-private) 접근수준으로 지정된 요소는 그 요소가 구현된 소스파일 내부에서만 사용할 수 있다. 해당 소스파일 외부에서 값이 변경되거나 함수를 호출하면 부작용이 생길 수 있는 경우에 사용하면 좋다.

비공개 접근수준 – private

비공개(Private) 접근수준은 가장 한정적인 범위이다. 비공개 접근수준으로 지정된 요소는 그 기능을 정의하고 구현한 범위 내에서만 사용할 수 있다. 비공개 접근수준으로 지정한 기능은 심지어 같은 소스파일 안에 구현한 다른 타입이나 기능에서도 사용할 수 없다.

접근제어 구현 참고사항

모든 타입에 적용되는 접근수준의 규칙은 ‘상위 요소보다 하위 요소가 더 높은 접근수준을 가 질 수 없다’이다.

비공개 접근수준으로 정의한 구조체 내부의 프로퍼티로 내부수준이나 공개수준을 갖는 프로퍼티를 정의할 수 없다. 또, 함수의 매개변수로 특정 접근수준이 부여된 타입이 전달되거나 반환된다면, 그 타입의 접근수준보다 함 수의 접근수준이 높게 설정될 수 없다.

// 잘못된 접근수준 부여

private class AClass {
    // 공개 접근수준을 부여해도 AClass의 접근수준이 비공개 접근수준이므로
    // 이 메서드의 접근수준도 비공개 접근수준으로 취급된다.
    public func someMethod() {
        // ...
    }
}
// AClass의 접근수준이 비공개 접근수준이므로
// 공개 접근수준 함수의 매개변수나 반환 값 타입으로 사용할 수 없다.
public func someFunction(a: AClass) -> AClass {
    // 오류 발생!
    return a
}

private와 fileprivate

같은 파일 내부에서 private 접근수준과 fileprivate 접근수준은 사용할 때 분명한 차이가 있다. fileprivate 접근수준으로 지정한 요소는 같은 파일 어떤 코드에서도 접근할 수 있다.
반면에 private 접근수준으로 지정한 요소는 같은 파일 내부에 다른 타입의 코드가 있더라도 접근이 불가능하다. 그러나 자신을 확장하는 익스텐션(extension) 코드가 같은 파일에 존재하는 경우에는 접근할 수 있다.

 public struct SomeType {
       private var privateVariable = 0
       fileprivate var fileprivateVariable = 0
}
// 같은 타입의 익스텐션에서는 private 요소에 접근 가능
extension SomeType {
    public func publicMethod() {
        print("\(self.privateVariable), \(self.fileprivateVariable)")
    }
    private func privateMethod() {
        print("\(self.privateVariable), \(self.fileprivateVariable)")
    }
    fileprivate func fileprivateMethod() {
        print("\(self.privateVariable), \(self.fileprivateVariable)")
    }
}
struct AnotherType {
    var someInstance: SomeType = SomeType()
    mutating func someMethod() {
        // public 접근수준에는 어디서든 접근 가능
        self.someInstance.publicMethod() // 0, 0
        // 같은 파일에 속해 있는 코드이므로 fileprivate 접근수준 요소에 접근 가능
        self.someInstance.fileprivateVariable = 100
        self.someInstance.fileprivateMethod() // 0, 100
        // 다른 타입 내부의 코드이므로 private 요소에 접근 불가! 오류!
        // self.someInstance.privateVariable = 100
        // self.someInstance.privateMethod()
    }
}
var anotherInstance = AnotherType()
anotherInstance.someMethod()

읽기 전용 구현

구조체 또는 클래스를 사용하여 저장 프로퍼티를 구현할 때는 허용된 접근수준에서 프로퍼티 값을 가져갈 수 있다. 값을 변경할 수 없도록 구현하고 싶다면 설정자(Setter)만 더 낮은 접근수준을 갖도록 제한할 수 있다. 요소의 접근수준 키워드 뒤에 {접근수준}(set)처럼 표현하면 설정자의 접근수준만 더 낮도록 지정해줄 수 있다.
설정자 접근수준 제한은 프로퍼티, 서브스크립트, 변수 등에 적용될 수 있으며, 해당 요소의 접근수준보다 같거나 낮은 수준으로 제한해주어야 한다.

public struct SomeType {
    // 비공개 접근수준 저장 프로퍼티 count
    private var count: Int = 0
    // 공개 접근수준 저장 프로퍼티 publicStoredProperty
    public var publicStoredProperty: Int = 0
    // 공개 접근수준 저장 프로퍼티 publicGetOnlyStoredProperty
    // 설정자는 비공개 접근수준
    public private(set) var publicGetOnlyStoredProperty: Int = 0
    // 내부 접근수준 연산 프로퍼티 internalComputedProperty
    internal var internalComputedProperty: Int {
        get {
            return count
        }
        set {
            count += 1
        }
    }
    // 내부 접근수준 저장 프로퍼티 internalGetOnlyComputedProperty
    // 설정자는 비공개 접근수준
    internal private(set) var internalGetOnlyComputedProperty: Int {
        get {
            return count
        }
        set {
            count += 1
        }
    }
}

var someInstance: SomeType = SomeType()
// 외부에서 접근자, 설정자 모두 사용 가능
print(someInstance.publicStoredProperty)    // 0
someInstance.publicStoredProperty = 100
// 외부에서 접근자만 사용 가능
print(someInstance.publicGetOnlyStoredProperty) // 0
//someInstance.publicGetOnlyStoredProperty = 100    // 오류 발생
// 외부에서 접근자, 설정자 모두 사용 가능
print(someInstance.internalComputedProperty)    // 0
someInstance.internalComputedProperty = 100
// 외부에서 접근자만 사용 가능
print(someInstance.internalGetOnlyComputedProperty)     // 1
//someInstance.internalGetOnlyComputedProperty = 100    // 오류 발생

0개의 댓글