[Swift] Access Control


Access Control


접근 제어

  • 코드의 세부 구현 내용을 숨기는 것이 가능하도록 만드는 개념
    • 객체지향 -> 은닉화가 가능해짐
    • 언어마다 약간씩의 차이가 있음

접근 제어가 필요한 이유

  • 원하는 코드를 감춰 놓을 수 있음
  • 코드의 영역을 분리시켜서, 효율적 관리 가능
  • 컴파일 시간이 줄어듦
    (컴파일러가 어느 범위에서만 해당 변수가 쓰이는지를 인지 가능)

접근 제어의 수준

키워드접근 수준에 대한 범위특징제한 정도
open다른 모듈에서 접근 가능
(상속/재정의 가능)
클래스의 가장 넓은 수준
(클래스에서만 사용 가능)
개방적
public다른 모듈에서 접근 가능
(상속 재정의 불가)
구조체/열거형의 가장 넓은 수준
(구조체는 상속 불가)
기본 타입의 설정 수준(Int, String 등)
↑
internal같은 모듈에서만 접근 가능
(디폴트 설정)
따로 명시하지 않는 경우의 기본 수준↕
fileprivate같은 파일 내에서만 접근 가능 ↓
private같은 scope 내에서만 접근 가능 폐쇄적
  • 모듈(module) : 프레임워크, 라이브러리, 앱 등 import해서 사용할 수 있는 외부의 코드
  • 모듈을 만들어서 배포하려면, public이상으로 선언해야 함

접근 제어를 가질 수 있는 요소

  • 타입 (클래스/구조체/열거형/스위프트 기본타입 등)
  • 변수 / 속성
  • 함수 / 메서드 (생성자, 서브스크립트 포함)
  • 프로토콜도 특정 영역으로 제한될 수 있음

접근 제어의 기본 원칙

타입은 타입을 사용하는 변수(속성)나, 함수(메서드)보다 높은 수준으로 선언되어야 함

변수와 변수가 사용하는 타입

var some: String = "접근 가능"
// some -> 변수 (internal)
// String -> 타입 (public)

함수와 함수 내부에서 사용하는 타입
(파라미터, 리턴 타입)

internal func sFunc(a: Int) -> Bool {
    print(a)
    print("hello")
    return true
}
// internal func -> 함수 (internal)
// print() -> 정수, 문자열, Bool (public)
  • 자신보다 내부에서 더 낮은 타입을 사용하면 접근을 하지 못해서 사용 불가

관습적인 패턴

// 속성(변수)를 선언시 private으로 외부에 감추려는 속성은 _(언더바)를 사용해서 이름 지음
class SomeOtherClass {
    private var _name = "이름"  // 쓰기 - private
    
    var name: String {  // 읽기 - internal
        return _name
    }
}

커스텀 타입의 접근 제어

타입의 내부 멤버는 타입 자체의 접근 수준을 넘을 수 없음

// 타입의 접근 제어 수준은 (해당 타입)멤버의 접근 제어 수준에 영향을 미침
// ex. 타입이 internal 로 선언 되면 내부의 멤버는 internal이하(internal / fileprivate / private)로 설정됨


public class SomePublicClass {                         // 명시적인 public 선언
    open var someOpenProperty = "SomeOpen"             // open 이라고 설정해도 public으로 작동
    public var somePublicProperty = "SomePublic"
    var someInternalProperty = "SomeInternal"          // 원래의 기본 수준
    fileprivate var someFilePrivateProperty = "SomeFilePrivate"
    private var somePrivateProperty = "SomePrivate"
}

let somePublic = SomePublicClass()
somePublic.someOpenProperty
somePublic.somePublicProperty
somePublic.someInternalProperty
somePublic.someFilePrivateProperty  // 같은 파일 안이기 때문에 접근 가능
// somePublic.somePrivateProperty  // private -> 접근 불가

내부 멤버의 접근 제어 수준

// 타입의 접근 수준이 높다고, 내부 멤버의 접근 수준이 무조건 따라서 높아지는 것 아님

open class SomeClass {
    var someProperty = "SomeInternal"
    // internal 임 -> 클래스와 동일한 수준을 유지하려면 명시적으로 open선언 필요
}

상속과 확장의 접근 제어

상속 관계 (Subclassing)의 접근 제어

  • 타입 관련
    • 상속해서 만든 서브클래스는 상위클래스보다 더 높은 접근 수준을 가질 수는 없음
  • 멤버 관련
    • 동일 모듈에서 정의한 클래스의 상위 멤버에 접근가능하면, (접근 수준 올려서) 재정의(override)도 가능
public class A {
    fileprivate func someMethod() {}
}

// public이하의 접근 수준만 가능(public/internal/fileprivate)
internal class B: A {
    // 접근 수준 올려서 재정의 가능
    override internal func someMethod() {  
        super.someMethod()
        // (더 낮아도) 모듈에서 접근가능하기 때문에 호출가능
    }
}

확장 (Extension)의 접근 제어

// 기본법칙 - 원래 본체와 동일한 접근 수준을 유지하고, 본체의 멤버에는 기본적인 접근 가능

public class SomeClass {
    private var somePrivateProperty = "somePrivate"
}

extension SomeClass {   // public으로 선언한 것과 같음
    // 본체의 멤버가 private이더라도 접근 가능
    func somePrivateControlFunction() {
        somePrivateProperty = "접근 가능"
    }
}

속성과 접근 제어

  • 속성의 읽기 설정(getter)과 속성의 쓰기 설정(setter)의 접근제어
  • 저장, 계산 속성의 읽기와 쓰기의 접근 제어 수준을 구분해서 구현 가능
// 일반적으로 밖에서 쓰는 것(setter)은 불가능하도록 구현하는 경우가 많음

struct TrackedString {
    private(set) var numberOfEdits = 0
    // setter에 대해서만 private 선언
    // 자동으로 internal으로 선언
    
    // 속성 관찰자
    var value: String = "시작" {
        didSet {
            numberOfEdits += 1
        }
    }
}

var stringToEdit = TrackedString()

// 외부에서 직접설정하는 것은 불가능 (읽는 것은 가능)
stringToEdit.numberOfEdits1 = 3  // 직접 설정 불가 (에러)
print(stringToEdit.numberOfEdits)  // 읽기 가능
  • 변수 및 속성, 서브스크립트에 쓰기(setter)수준을 읽기(getter)수준보다 낮은 접근 수준으로 설정 가능
  • 읽기의 수준보다 쓰기의 수준이 더 높을 순 없음. 쓰기는 데이터를 바꾸는 동작이기 때문에 더 높은 위험성 가짐
    (다른 코드에 영향을 미칠 수 있음)

속성의 읽기 설정과 속성의 쓰기 설정에 대해 각각 명시적으로 선언도 가능

internal private(set) var numberOfEdits

1) 속성의 읽기설정(getter)은 - internal
2) 속성의 쓰기설정(setter)은 - private(set)

-> 저장속성 / 계산속성 모두에 설정 가능


참고

Ellen Swift Class






© 2021. by hminkim