Swift - 접근제한자

이한솔·2023년 9월 28일
0

Swift 문법 🍎

목록 보기
28/32

접근제한자(Access Control)

접근 제한자는 다른 소스 파일이나 모듈의 코드에서 코드 일부에 대한 액세스를 제한한다.
이 기능은 코드의 세부 구현 사항을 숨기고, 해당 코드를 접근하고 사용할 수 있는 기본 인터페이스를 지정할 수 있게 한다.
코드의 세부 구현 사항을 숨기기때문에 객체 지향의 은닉화가 가능해진다.

💡 은닉화란?
객체 외부에서 객체 내의 자료의 접근을 제한하고 데이터를 수정, 조작하는 동작은 내부에 두고 접근(getter), 설정(setter)하는 메소드로 결과만 받는것이다.
외부에서는 내부의 움직임을 알 수가 없으며 데이터에 어떤 값이 있는지, 어떤 변화가 일어나는지 알 수 없으며 단지 데이터의 접근을 메서드(setter, getter)를 통해 결과만 받을뿐이다.
한마디로, 다른 소스파일 및 모듈의 코드에서 코드 일부에 대해서 못 보게 막아버리는 것이다. 접근 지정자는 은닉화를 가능하게 해줘서, 다른 사용자들이 딱 사용해야하는 정보만 볼 수 있도록 해준다.

접근제한자를 사용할 수 있는 곳

접근 제한자는 클래스, 구조체, 열거형 같은 개별 타입뿐만 아니라 해당 타입에 속하는 프로퍼티, 메소드, 이니셜라이저에 사용 가능하다.

프로토콜은 전역 상수, 변수, 함수처럼 특정 컨텍스트로 제한될 수 있다.

모듈 & 소스파일

모듈: 하나의 코드 묶음 (하나의 프레임워크, 하나의 라이브러리, 하나의 애플리케이션)
swift의 import키워드를 사용하여 다른 모듈에서 가져올 수 있는 framework 또는 응용 프로그램같은 라이브러리들이 모두 모듈이다.

소스파일: .swift파일 하나의 단위



Access Level

🔓 open, public

엔티티를 정의한 모듈의 모든 소스 파일 내뿐만 아니라 정의한 모듈을 가져다 쓰는 다른 모듈의 소스파일에서도 사용할 수 있다. 일반적으로 framework에 공용 인터페이스를 지정할 때 public, open 접근을 사용한다.

open

public보다 더 개방적인 접근수준을 지정한다. class와 class 멤버에만 사용될 수 있다.
모듈 밖에서도 클래스를 상속할 수 있고, 클래스의 멤버를 서브클래싱이나 override 할 수 있다. 명시적으로 open으로 표시하면 해당 클래스를 super class로 사용하는 다른 모듈의 코드의 영향을 고려하면서 코드를 짤 수 있다.

public

어디서든 사용될 수 있는 접근수준을 지정한다.
정의된 모듈 내에서만 서브클래싱이나 override 가능하다.
외부 상속은 불가능하다. (open을 제외한 모든 접근이 동일하다.)


🔒 internal

엔티티가 정의된 모듈의 모든 소스 파일 내에서 상속, 재정의, 사용할 수 있지만, 외부의 소스파일에서는 접근할 수 없다. 정의된 모듈 안에서만 사용 가능 일반적으로 app이나 framework의 내부 구조를 정의할 때 internal 접근을 사용한다.

아무런 접근 제한자가 선언되지 않았다면 기본적으로 모든 요소에 암묵적으로 지정되는 접근수준인 internal 접근 수준을 가지게 된다.


🔐 fileprivate, private

fileprivate 접근을 사용하면 해당 세부 정보가 전체 파일 내에서 사용될 때 특정 기능의 구현 세부 정보를 숨길 수 있습니다. private 접근은 단일 정의 내에서만 사용되는 특정 기능 조각의 구현 상세 내역을 숨길 수 있습니다.

fileprivate

같은 파일 내의 다른 위치에서 상속, 재정의, 사용이 가능하고 다른 파일에서는 접근할 수 없다.
swift는 하나의 .swift 파일 안에 여러 개의 타입을 선언할 수 있는 특성을 가지고 있다. fileprivate은 이러한 파일 스코프를 활용하여 특정 기능의 세부 구현을 파일 내에서만 공유하고 전체 파일 내에서 특정 기능의 세부 구현 정보를 숨기고자 할 때 사용한다.

private

같은 스코프 안에서만 액세스 할 수 있다.
같은 클래스나 구조체 내에서만 사용할 수 있으며, 외부에서는 접근할 수 없습니다. 해당 타입의 내부 상태나 구현의 일부를 외부로부터 숨기고자 할 때 유용하다. 정보 은닉의 관점에서 중요한 역할을 한다.
swift4 이후부터 같은 소스파일 안에서의 extension에도 private를 사용할 수 있다.



은닉 정도

(제약 적음) open > public > internal > filePrivate > private (제약 많음)
모든 타입에 적용되는 접근지정자 규칙은 상위 요소보다 하위 요소가 더 높은 접근수준을 가질 수 없다.

예를 들면 private으로 선언된 클래스에서 public 프로퍼티나 함수를 가질 수 없고, 매개변수나 반환값은 함수의 접근지정자보다 같거나 높아야 하고,
열거형의 원시 값의 타입은 열거형 자체의 접근수준보다 높아야 한다.


💡 언제 접근 제한자를 사용해야 할까?

주로 라이브러리나 프레임워크와 같이 외부에서 사용되는 모듈을 만들 때 사용한다. 보통 앱을 만들때는 작성한 소스코드가 외부에서 사용될 일이 없기 때문에 굳이 사용할 필요가 없다.
프로젝트를 만들 때 접근 제한자를 명시해가며 소스코드를 작성할 필요는 없지만 앱 자체적으로 구현 세부 정보를 다른 코드로부터 숨기려면 fileprivate이나 private를 사용하면 된다.
그리고 어플리케이션이나 작은 프로젝트의 경우, 명시적인 접근 제한자를 사용하지 않더라도 swift에서 기본으로 제공되는 기본 접근 수준이 충분히 잘 동작할 수 있다. 단일 타겟 앱에서는 명시적인 접근 제한자를 사용할 필요성이 적다.



예시코드

// ModuleA.swift
// open 접근 수준, 모듈 외부에서도 상속 가능하도록 지정
open class BaseClass {
    // open 접근 수준
    open func publicMethod() {
        print("This is a public method")
    }

    // internal 접근 수준
    internal var internalProperty = 10

    // fileprivate 접근 수준
    fileprivate func fileprivateMethod() {
        print("This is a fileprivate method")
    }

    // private 접근 수준
    private var privateProperty = "private property"

    // private 접근 수준
    private func privateMethod() {
        print("This is a private method")
    }

    // BaseClass 내부에서만 접근 가능한 중첩된 클래스
    private class NestedClass {
        func nestedMethod() {
            print("This is a nested method")
        }
    }
}


// ModuleB.swift
import ModuleA

// ModuleB에서 ModuleA의 BaseClass를 상속한 DerivedClass 정의, public 접근 수준
public class DerivedClass: BaseClass {
    // public 접근 수준
    public func someMethod() {
        print("This is a public method in DerivedClass")
    }

    // Private 접근 수준
    private func privateMethodInDerivedClass() {
        print("This is a private method in DerivedClass")
    }
}


// Main.swift
import ModuleA

let baseObject = BaseClass()
baseObject.publicMethod() // Public 접근 수준
print(baseObject.internalProperty) // internal 접근 수준
baseObject.fileprivateMethod() // fileprivate 접근 수준
// baseObject.privateProperty // 접근 불가능: 'privateProperty' is inaccessible due to 'private' protection level
// baseObject.privateMethod() // 접근 불가능: 'privateMethod()' is inaccessible due to 'private' protection level
// let nestedObject = BaseClass.NestedClass() // 접근 불가능: 'NestedClass' is inaccessible due to 'private' protection level

let derivedObject = DerivedClass()
derivedObject.someMethod() // Public 접근 수준
// derivedObject.privateMethodInDerivedClass() // 접근 불가능: 'privateMethodInDerivedClass()' is inaccessible due to 'private' protection level

0개의 댓글