[Swift] - Access Control(접근 제어)

longlivedrgn·2023년 1월 1일
0

swift문법

목록 보기
28/36
post-thumbnail

Access Control(접근제어)는 다른 소스 파일 및 모듈의 코드에서, 코드의 일부에 대한 접근을 제한합니다.

  • 모듈 → 시스템(혹은 프로그램)이나 제품 등에서 개별적인 기능이나 역할을 가진 부품, 요소/ import 시킬 수 있는 요소(Framework라고도 할 수 있다 ex. UIkit)
  • 소스 파일 → 모듈 내의 단일 swift 소스 파일(ex. viewcontroller.swift)

Access levels

  • 아래로 갈수록 접근하기가 어려워진다!
  1. open & public
  2. internal
  3. file-private
  4. private

Open VS Public

예를 통해서 한번 Open 과 Public의 차이점을 알아보자.

서브 클래싱 관점.

  • 먼저 내가 외부의 framework MiroFramework를 만들어줬다고 하자. 그리고 그 안에 각각의 open class와 Public class를 만들어줬다.
// MiroFramework라면
open class OpenClass {
    public init(){}
}

public class PublicClass {
    public init(){}
}
  • 그리고 위와 같은 외부 framework를 import받아 open class instance와 public class instance를 만들어보자.
import MiroFramework

class ViewController: UIviewcontroller {
    override func viewDidLoad() {
        super.viewDidLoad()
        let openClassInstance = OpenClass()
        let publicClassInstance = PublicClass()
    }
}
  • 그리고 아래와 같이 subclassing을 진행하면 open 제어 레벨의 경우에는 외부 framework에서도 서브 클래싱이 가능하지만, public 제어 레벨의 경우에서는 서브 클래싱이 불가능하다.
class SubClass: OpenClass() // OK!

class SubClass: PublicClass() // Error!

그러면 public 제어 레벨 및 internal, file-private, private 경우에는 싹 다 서브클래싱이 불가능할까?

그건 아니다! 같은 framework안에서는 서브클래싱이 가능하다. 즉, MiroFramework안에서는 서브클래싱이 가능하다.

by. Zeddios

📌 open class : Framework내부, Framework외부 (즉 어디서든) 서브클래싱이 가능
public class와 더 제한적인 접근 수준들(internal, File-private, private class) : Framework내부에서만 서브클래싱이 가능

override 관점.

애초에 public의 경우 subclass로 만들수가 없으므로 open 접근제어만 고려해보자!

  • 아래와 같이 open func을 만들어주자
// MiroFramework에서
open class OpenClass {
    public init(){}
    open func someMethod(){}
}
  • 아래와 같이 override를 해도 에러가 나지않는다.
// error
class SubClass: OpenClass{
    override func someMethod(){
        print("")
    }
}

반면에!!

  • 아래와 같이 public func으로 설정을 했을 경우
// MiroFramework에서
open class OpenClass {
    public init(){}
    public func someMethod(){}
}
  • override 를 할 경우 에러가 난다!
// OK
class SubClass: OpenClass{
    override func someMethod(){
        print("")
    }
}

그러나, 앞서 서브 클래싱과 같게 같은 framework내에서는 override가 가능하다.

📌 **open : class, class 멤버는 정의된 모듈 내에서나, 그 모듈을 import하는 외부 모듈에서나 서브클래싱이나 override가 잘 된다"**

public, internal, File-private, private : class, class멤버는 정의된 모듈 내에서만 서브클래싱이나 override가 된다"

Internal

⇒ internal 접근은 엔티티가 정의 모듈의 모든 소스 파일 내에서 사용되지만, 해당 모듈 외부의 소스파일에서는 사용되지 않도록 합니다. 일반적으로 App이나  Framework의 내부 구조를 정의할 때 internal 접근을 사용합니다.

즉, 모듈 내에서만 사용이 가능하다!

기본 default가 싹 다 internal이다, 따라서 internal이라는 단어가 없어도 다 internal인 것!

예를 통해서 이해해보자

  • 아래의 OpenClass는 Internal class이며, someMethod는 internal method이다.
// MiroFramework에서
class OpenClass {
    public init(){}
    func someMethod(){}
}
  • 따라서 아래와 같이 MiroFramework외부에서 OpenClass를 만드려고하면 error가 나오게 된다!
import MiroFramework

class ViewController: UIviewcontroller {
    override func viewDidLoad() {
        super.viewDidLoad()
				// error
        let openClassInstance = OpenClass()
    }
}
  • 그럼 아래와 같이 OpenClass를 Open 제어 레벨로 설정해보자
// MiroFramework에서
open class OpenClass {
    public init(){}
    func someMethod(){}
}
  • 그러면 internal로 설정된 someMethod에 의해서 에러가 생기게된다!
import MiroFramework

class ViewController: UIviewcontroller {
    override func viewDidLoad() {
        super.viewDidLoad()
        let openClassInstance = OpenClass()
				// 에러
				openopenClassInstance.someMethod()
    }
}

File-private

internal이 모듈 내에서 사용이 가능하다면, file-private의 경우 소스 파일 내에서만 사용이 가능하다.

  • 아래와 같이 fileprivate class를 정의해보자
fileprivate class FileprivateClass{

    public init() {}

}
  • 같은 파일 내에서도 private을 붙혀서 instance를 만들어줘야하고, private을 붙혀줘야지 서브클래싱이 가능하다.
private var fileprivateInstance = FileprivateClass()
private class A : FileprivateClass {} // Private or fileprivate을 붙혀준다.
  • 단, override를 할 때에는 아무것도 안 붙혀줘도 된다.
open class OpenClass {

    fileprivate func someMethod() {}

}

class A : OpenClass{

    override func someMethod() {

        print("Hello")

    }

}

Private

⇒ private접근을 사용하면 단일 정의 내에서만 사용되는 특정 기능 조각의 구현 상세 내역을 숨길 수 있습니다.

  • 아래와 같이 Private class를 설정해주면, private을 통하여 instance를 생성할 수 있다. 이렇게 하지 않으면 instance 생성 불가능!
private class PrivateClass{

    public init() {}

}
private let someInstance = PrivateClass() //OK
  • 그리고 만약 아래와 같이 property에 접근하려고 하면 error가 나게 된다.
private class PrivateClass{

    public init() {}

    private var name = "Miro"
}

class Test {

    private let someInstance = PrivateClass()

    func someMethod(){

        print(**someInstance.name**) //Error!

    }

}

총정리

  • Public/Open -> 모듈 외부에서도 사용가능,
  • internal -> 같은 모듈 및 프로젝트에서 사용가능
  • fileprivate -> 같은 소스파일(swift)
  • private -> 같은 클래스 { }안에 있어야된다.

Public, Open 제어자

  • 서로 다른 모듈에 있는 메소드, 프로퍼티에 접근을 할 수 있다.
  • 단, import를 해주어야된다.

예)

// module contactManager (target contactManager)
public var name: String = "module A" 
var number: Int = 1

// module ContactManagerUI (target ContactManagerUI)
import contactManager
print(name) // OK!
print(number) // error

Target membership의 활용

  • import를 해줄 필요가 없이(module을 만들어 줄 필요가 없이), 바로 외부 module(target)에서 해당 target의 파일에 접근이 가능하다.
  • internal 수준의 메소드, 프로퍼티도 접근가능하다.
  • 아래의 코드의 경우, 해당 swift 파일은 ContactManagerUI에서 접근이 가능하다!(internal 메소드, 프로퍼티도 접근 가능!)

UnitTest에서 @testable

  • 원래 import를 하면 public, open 메소드, 프로퍼티만 접근이 가능하지만
  • @testable를 추가해주면 internal 메소드, 프로퍼디도 접근이 가능해진다!

🥳출처
Access Control

0개의 댓글