적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

Swift iOS 앱 개발/Swift

[Swift] Access Control 접근 제어자 종류 및 사용

hongssup_ 2022. 5. 11. 12:13
반응형

 

접근 제어자 사용하는 이유

- 외부로부터 데이터를 보호하기 위해서

- 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서

더보기

* 참고 : 은닉화(Hiding)란?

- 객체지향 개발에서 외부로부터 데이터를 보호하기 위해, 객체 외부에서 객체 내 자료로의 접근을 제한하고, 데이터를 수정하거나 조작하는 동작은 접근자(getter, setter)를 통해 결과만 받는 것. 외부에서의 직접 접근은 막고 메서드를 통해 간접 접근할 수 있도록.

 

예를 들어 public class 안의 변수 int hour가 0~23 사이의 값을 가져야할 때,

변수의 접근 제어자를 private 으로 하여 외부에서 직접 접근하지 못하도록 하고,

setHour 메서드를 통해 간접적으로 접근할 수 있도록 하여 값을 보호할 수 있다. 

public class Time {
    private int hour;
    
    private boolean isValidHour(int hour) { //클래스 내부에서만 사용되는 유효성 확인 메서드
        return (hour < 0 || hour > 23);
    }
    public void setHour(int hour) { //유효성 확인 후 변수 설정
        if isValidHour(hour) return;
        this.hour = hour;
    }
    public int getHour() { return hour; }
}

Time().hour = 25; 와 같이 값을 직접 변경하는 게 아니라
Time().setHour(21); Time.getHour(); 이런 식으로 get set 메서드를 통한 간접 접근이 가능하다. 

참고 : youtube - 남궁성의 정석코딩 

 

Access Control (접근 제어)

다른 소스파일 및 모듈의 코드에서, 코드의 일부에 대한 액세스(접근)을 제한하는 것.

individual types (classes, structures, enumerations) 뿐 아니라 해당 타입에 속하는 properties, methods, initializers and subscripts 에 대해 특정 접근 레벨을 지정할 수 있다.

 

Modules and Source Files

Swift 접근 제어 모델은 모듈소스 파일의 개념을 기반으로 한다. 

* 모듈 : 시스템(혹은 프로그램)이나 제품 등에서 개별적인 기능이나 역할을 가진 부품, 요소 등을 칭한다 - 나무위키

Xcode의 각 build target(예: app bundle 또는 framework)은 Swift에서 별도의 모듈로 처리되는데, 보통 import로 불러와 사용하는 것들을 모두 모듈이라고 이해하면 될듯? 

소스 파일은 말그대로 Swift 소스 코드 파일. 각 소스 파일 마다 individual types 를 정의하는 것이 일반적이지만, 하나의 소스 파일에는 여러 타입, 함수 등에 대한 정의가 포함될 수 있다. 

 

Access Levels 

Swift는 코드 내의 엔티티에 대해 5가지 제어 단계를 제공한다. open - public - internal - fileprivate - private

• open, public (개방, 공개 접근수준) 

엔티티가 정의된 모듈의 모든 소스 파일 내에서 사용 가능 + 정의한 모듈을 가져오는 다른 모듈의 소스 파일에서도 사용 가능

일반적으로 공용 인터페이스를 지정할 때 open / public 접근을 사용. 

open 접근은 클래스 및 클래스 멤버에만 적용 가능하며, (struct와 enum은 public 부터 가능)

모듈 외부의 코드에서도 서브클래싱(subclass) 및 재정의(override)가 허용된다는 점이 public과의 차이.  

• internal (내부) - default access level

엔티티가 정의된 모듈의 모든 소스 파일 내에서 사용할 수 있지만, 해당 모듈 외부의 소스 파일에서는 사용 불가.

일반적으로 앱 또는 프레임워크의 내부 구조를 정의할 때 internal 사용. 

모든 요소의 기본 지정 접근수준 (따로 표기해줄 필요 없음)

• fileprivate (파일외부 비공개)

엔티티가 정의된 소스파일 내부에서만 사용 가능

해당 소스파일 외부에서 값이 변경되너나 함수 호출하면 부작용이 생길 수 있는 경우 사용하면 좋음

• private (비공개)

엔티티를 정의하고 구현한 범위 내에서만 사용 가능

 

Access Levels for Single-Target Apps 

간단한 Single-Target 앱을 작성할 때는 앱 모듈 외부에서 코드를 사용할 필요가 없기 때문에 굳이 따로 액세스 수준을 지정할 필요 없이 기본값 internal을 사용하거나, 필요에 따라 코드 일부를 fileprivate 또는 private으로 작성할 수 있다. 

Access Levels for Frameworks

프레임워크를 개발할 때, 프레임워크 API(application programming interface)로 사용될 공용 인터페이스(public-facing interface)는 다른 모듈에서 보고 접근할 수 있도록 open / public 으로 작성한다. 

* API (application programming interface 응용 프로그램 프로그래밍 인터페이스) - 컴퓨터나 컴퓨터 프로그램(소프트웨어) 사이의 연결

   UI (user interface 사용자 인터페이스) - 사람과 컴퓨터 사이의 연결

Access Levels for Unit Test Targets

단위 테스트 타겟이 있는 앱을 작성할 때는, 테스트를 위해 해당 모듈에서 사용할 수 있도록 작성되어야 한다. 

기본적으로는 open / public으로 표시된 엔티티만 다른 모듈에 엑세스할 수 있지만, unit test target은 @testable 속성을 표시해주면 모든 internal 엔티티에 접근이 가능하다.

 

Subclassing 

서브클래스는 슈퍼클래스보다 더 제한적이거나 같은 접근 수준만 가질 수 있다. 

class A { }
public class B : A { //Error }

위 처럼 서브클래스가 슈퍼클래스보다 더 높은 접근 레벨을 가질 수는 없지만, 

아래처럼 더 제한적인 접근 수준은 가질 수 있다. 

public class A { }
internal class B : A { }

override를 사용하면, 상속된 클래스 멤버가 슈퍼클래스 버전보다 덜 제한적인 접근 수준을 가질 수도 있다. 

public class A { 
    filepivate func someMethod() {}
}
internal class B: A {
    override internal func someMethod() {}
}

 

Getters and Setters

setter에 해당 getter보다 제한적인 접근 수준을 부여하여 해당 변수, 프로퍼티 또는 서브스크립트의 읽기/쓰기 범위를 제한할 수 있다. 

struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}

private(set) 을 변수 앞에 붙여주면, 해당 변수는 선언된 구조체 코드 내에서만 설정(set)할 수 있다는 것을 의미. 

즉, 외부에서도 접근은 가능하여 읽을 수는 있지만 set만 private. 

다른 소스 파일에서 

var trackedString = TrackedString()

print(trackedString.numberOfEdits) 

이렇게 값을 읽어오는 건 가능하지만 

trackedString.numberOfEdits = 10 이렇게 직접 값을 넣으려고 하면 에러가 난다. 

 

Setter만 더 낮은 접근수준을 갖도록 제한할 수 있다.

private(set) var property: Type

접근(getter)은 public이지만 설정(setter)은 private으로 할 수도 있다.

public private(set) var property: Type

 

 

 

참고 : Swift 문서 - Access Control, ZeddiOS

728x90
반응형