본문 바로가기

iOS-Study

iOS Study : 7주차 - 접근제어(모듈과 소스파일, 접근수준, 접근제어 구현 참고사항, private와 fileprivate, 읽기 전용 구현)

접근제어

  • 코드끼리 상호작용을 할 때 파일 간 또는 모듈 간에 접근을 제한할 수 있는 기능
  • 접근제어를 통해 코드의 상세 구현은 숨기고 허용된 기능만 사용하는 인터페이스를 제공할 수 있다.

접근제어의 필요성

  • 외부에서 보거나 접근하면 안되는 코드가 있는 경우 꼭 필요한 부분만 제공해야 하는데 전체 코드가
    노출될 가능성이 있을 때 접근제어를 이용한다.

 

모듈

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

소스파일

  • 소스파일은 하나의 스위프트 소스 코드 파일을 의미한다.
  • 스위프트에서 보통 파일 하나에 타입 하나만 정의하지만, 때로는 소스파일 하나에 여러 타입이나 함수 등
    많은 것을 정의하거나 구현할 수도 있다.

 

접근수준

  • 접근제어는 접근수준 키워드를 통해 구현할 수 있다.
  • 각 타입에 특정 접근수준을 지정할 수 있고, 타입 내부의 프로퍼티, 메서드, 이니셜라이저, 서브스크립트 각각에도
    접근수준을 지정할 수 있다.
  • 접근수준을 명시할 수 있는 키워드는 open, public, internal, fileprivate, private 다섯 가지가 있다.
  • 스위프트의 접근 수준은 기본적으로 모듈과 소스파일에 따라 구분한다.
접근 수준 키워드 범위  비고
개방 접근수준 open 모듈 외부까지 클래스에서만 사용
공개 접근수준 public 모듈 외부까지  
내부 접근수준 internal 모듈 외부  
파일외부비공개 접근수준 fileprivate 파일 내부  
비공개 접근수준 private 기능정의 <-> 내부  

 

공개 접근수준 - public

  • public 키워드로 접근수준이 지정된 요소는 어디서든 쓰일 수 있다.
  • 주로 프레임워크에서 외부와 연결될 인터페이스를 구현하는데 많이 쓰인다.

 

개방 접근수준 - open

  • open 접근수준은 public 접근수준 이상으로 높은 접근수준이며, 클래스와 클래스의 멤버에서만 사용할 수 있다.

공개 접근수준과 차이점

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

 

내부 접근수준 - internal

  • 기본적으로 모든 요소에 암묵적으로 지정하는 기본 접근수준이다.
  • 내부 접근수준으로 지정된 요소는 소스파일이 속해 있는 모듈 어디에서든 쓰일 수 있다.
    • 다만 그 모듈을 가져가 쓰는 외부 모듈에서는 접근할 수 없다.

 

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

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

 

비공개 접근수준 - private

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

 

접근제어 구현 참고사항

  • 모든 타입에 적용되는 겁근수준의 규칙은 상위 요소보다 하위 요소가 더 높은 접근 수준을 가질 수 없다.
    • 예시로 비공개 접근수준으로 정의한 구조체 내부의 프로퍼티로 내부수준이나 공개수준을 갖는
      프로퍼티를 정의할 수 없다.

 

private와 fileprivate

  • 같은 파일 내부에서 private와 fileprivate는 사용할 때 차이가 있다.
  • fileprivate 접근수준으로 지정한 요소는 같은 파일 어떤 코드에서도 접근이 가능하지만
    private 접근수준으로 지정한 요소는 같은 파일 내부에 다른 타입의 코드가 있더라도 접근이 불가능하다.
    • private의 경우 자신을 확장하는 익스텐션 코드가 같은 파일에 존재하는 경우에는 접근할 수 있다.
 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) 처럼 표현한다.
  • 설정자(Setter)접근수준 제한은 프로퍼티, 서브스크립트, 변수 등에 적용될 수 있고, 해당 요소의 접근 수준보다
    같거나 낮은 수준으로 제한해 주어야 한다.
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    // 오류 발생