궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [접근 제어 - open, public, internal, fileprivate, private]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

본 게시글은 yagom님의 Swift 프로그래밍 3판을 참고하여 작성되었습니다.

 

객체지향 프로그래밍인 Swift에서 '은닉화'는 중요한 개념이다. 이를 구현하기 위한 핵심 기능인 접근제어에 대해 알아보려고 한다.

접근제어

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

TIP
 
 

OOP (Object Oriented Programming)

추상화 - 공통의 속성이나 기능을 묶어 이름을 붙이는 것. 다른 객체들과 구분되는 핵심적인 특징들에만 집중해 복잡도를 관리할 수 있도록 함.

캡슐화 - 객체의 속성과 행위(메서드)를 하나로 묶고, 실제 구현 내용 일부를 외부에 감추어 은닉. 중요한 데이터를 보존, 보호하고 연관 있는 변수와 함수를 클래스로 묶는 작업을 함.

은닉화 - 객체에서 속성을 직접 접근하지 못하게 숨기는 것. 변수에 접근 지정자를 private로 지정. setter, getter를 사용해 변수의 접근을 제어함.

객체지향 프로그래밍 패러다임에서의 중요한 캡슐화와 은닉화를 구현하는 이유는 외부에서 직접 접근하거나 보이면 안 되는 코드가 있기 때문이다. 꼭 필요한 부분의 코드가 아닌 전체 코드가 노출될 가능성이 있을 때 접근제어를 사용한다.

모듈과 소스파일

Swift의 접근제어는 모듈 Module과 소스파일을 기반으로 설계되어있다.

 

모듈은 배포할 코드의 묶음 단위이다. 프레임워크나 라이브러리 또는 애플리케이션이 이 모듈 단위가 될 수 있다. import 키워드를 사용하여 불러온다.

 

소스파일은 하나의 Swift 소스 코드 파일을 의미한다. Swift에서도 보통 파일 하나에 하나의 타입만 정의하지만, 소스 파일 하나에 여러 타입(여러 개의 클래스, 구조체, 열거형 등)이나 함수 등 많은 것을 정의/구현 가능하다.

접근수준

접근제어는 접근수준 키워드를 통해 구현이 가능하다. 클래스, 구조체, 열거형등에 특정 접근수준을 지정할 수 있으며, 메서드, 이니셜 라이저, 서브 스크립트, 프로퍼티 각각에 접근수준을 지정할 수 있다. 

 

접근수준(Access Level) 종류

접근수준 키워드 접근도 범위 비고
개방 접근수준 open 높음



낮음
모듈 외부까지 클래스에서만 사용 가능
공개 접근수준 public  
내부 접근수준 internal 모듈 내부
파일외부비공개 접근수준 filePrivate
비공개 접근수준 private 기능 정의 내부

공개 접근수준  -  public

  • public 키워드로 지정된 요소는 어디에서든 사용 가능
  • 소스 파일/소스에 속해 있는 모듈, 그 모듈을 가져다 쓰는 모듈 등 모든 곳에서 사용 가능
  • 주로 프레임워크에서 외부와 연결될 인터페이스를 구현하는데 많이 쓰임
  • Swift 기본 요소는  보통 public 접근수준으로 구현되어있음
//인스턴스가 true 또는 false인 값 타입.
public struct Bool {
 // 기본 이니셜라이저 불리언 값을 false로 초기화
  print init()
}

개방 접근수준  -  open

  • 공개 접근수준 이상으로 높은 접근수준
  • 클래스와 클래스 멤버에서만 사용 가능
  • 공개 접근수준과 비슷하지만 차이점이 존재함

공개 접근수준과 개방 접근수준의 차이점

  • public 접근수준을 제외한 다른 모든 접근수준의 클래스는 그 클래스가 정의된 모듈 안에서만 상속 가능
  • open 접근수준의 클래스는 그 클래스가 정의된 모듈 밖에서도 상속 가능
  • public 접근수준을 제외한 다른 모든 접근수준의 클래스 멤버는 해당 멤버가 정의된 모듈 안에서만 override 가능
  • open 접근수준의 클래스 멤버는 해당 멤버가 정의된 모듈 밖의 다른 모듈에서도 override 가능

클래스를 개방 접근수준으로 명시한다는 건 '그 클래스를 다른 모듈에서도 부모 클래스로 사용하겠다는 목적으로 설계하고 코드를 작성했다'는 의미이다.

open class NSString: NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
   open var length: Int { get }
   open func character(at index: Int) -> unichar
   public init()
   public init?(coder aDecoder: NSCoder)
}

↪︎  Foundation 프레임워크에 정의되어 있는 개방 접근수준의 NSString 클래스

내부 접근수준  -  internal

  • internal 키워드로 지정된 요소는 소스파일이 속해 있는 모듈 어디에서든 사용 가능
  • internal 키워드는 생략해도 무관
  • 내부 접근수준은 모든 요소에 암묵적으로 지정하는 기본 접근 수준
  • 내부 접근수준으로 지정된 모듈을 가져다 쓰는 외부 모듈에서는 접근 불가
  • 외부에서 사용할 클래스나 구조체가 아님
  • 모듈 내부에서 광역적으로 사용할 경우 내부 접근수준을 지정함

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

  • fileprivate 키워드로 지정된 요소는 그 요소가 구현된 소스파일 내부에서만 사용 가능
  • 소스파일 외부에서 값이 변경되거나 함수를 호출하면 부작용이 생길 수 있는 경우에만 사용 권장

비공개 접근수준  -  private

  • private 키워드로 지정된 요소는 그 요소가 구현된 소스파일 내부에서만 사용 가능
  • 비공개 접근수준은 가장 한정적인 범위임
  • private로 지정한 기능은 심지어 같은 소스파일 안에 구현한 타른 타입이나 기능에서도 사용 불가

접근제어 구현 참고사항

  • 접근수준 공통 사항 : '상위 요소보다 하위 요소가 더 높은 접근수준을 가질 수 없다
  • 비공개 접근수준(private)으로 정의한 구조체 내부의 프로퍼티로 내부수준 또는 공개수준을 갖는 프로퍼티 정의 불가
  • 함수의 매개변수로 특정 접근수준이 부여된 타입이 전달/반환 되면, 그 타입의 접근수준보다 함수의 접근수준이 높게 설정 불가
  • 함수뿐 아니라 튜플의 내부 요소 타입도 튜플의 접근수준과 같거나 높아야 한다
  • 열거형의 각 case의 접근수준은 열거형 자체의 접근수준을 따른다
  • 열거형의 접근 수준보다 낮은 접근수준의 타입/연관 값의 타입이 올 수 없다
private class SomeClass {
    //public을 부여해도 SomeClass의 접근수준이 private 이므로
    //someMethod의 접근수준도 private 접근수준으로 취급
    public func someMethod() {
        // ...
    }
}

//someClass의 접근수준이 private 이므로
//public 접근수준 함수의 매개변수나 반환 값 타입으로 사용 불가.
public func someFunction(a: SomeClass) -> SomeClass {
    return a
}
//error: 매개변수가 private 타입을 사용하기 때문에 함수를 public로 선언할 수 없습니다.

↪︎  잘못된 접근수준

internal class InternalClass {}
private struct PrivateStruct {}

// 요소로 사용된 InteranlClass와 PrivateStruct의 접근수준이
// public보다 낮은 수준이기 때문에 사용 불가
public var publicTuple: (first: InternalClass, second: PrivateStruct) = (InternalClass(), PrivateStruct())

// 요소로 사용된 InteranlClass와 PrivateStruct의 접근수준이
// private와 같거나 높으므로 사용 가능
private var privateTuple: (first: InternalClass, second: PrivateStruct) = (InternalClass(), PrivateStruct())

↪︎  튜플의 접근 수준 

// AClass.swift와 Common.swift 파일이 같은 모듈에 속해있다는 전재 하에

// AClass.swift
class AClass {
    func internalMethod() {}  // internal 접근수준은 키워드 생략 가능
    fileprivate func filepriavateMethod() {}
    var interanlProperty = 0
    fileprivate var fileprivateProperty = 0
}

// Common.swift
let firstInstance: AClass = AClass()
firstInstance.internalMethod() //같은 모듈이기 때문에 호출 가능
firstInstance.interanlProperty = 1 // 같은 모듈이기 때문에 접근 가능
firstInstance.filepriavateMethod() // error: 다른 파일이기 때문에 호출 불가
firstInstance.fileprivateProperty = 1 // error: 다른 파일기이 때문에 접근 불가

↪︎  접근수준에 따른 접근 결과

 

TIP
 
 

프레임워크 및 그 외의 요소 접근수준
프레임워크를 만들 때는 다른 모듈에서 특정 기능에 접근할 수 있도록 API로 사용할 기능을 공개 접근수준인 public로 지정해주어야 한다. 그 외의 요소는 내부 접근수준인 interanl 이나 비공개 접근수준인 private 로 적절히 설정하면 된다.

열거형의 접근수준을 구현할 때는 열거형 내부의 각 case 별로 따로 접근수준을 부여할 필요 없이 각 case의 접근수준은 열거형 자체의 접근수준을 따른다. 또, 열거형의 원시 값 타입으로 열거형의 접근수준보다 낮은 접근수준의 타입이 올 수 없다.

private typealias NameValue = String
// 원시 값 사용 가능
private enum Name: NameValue {
    case 서근
}

private typealias NameValue = String
// NameValue가 Name보다 접근수준이 낮기 때문에 원시 값으로 사용 불가
enum Name: NameValue {
    case 서근
}

private와 fileprivate

같은 파일 내부에서 privatefileprivate 접근수준은 사용할 때 분명한 차이가 존재한다.

  • fileprivate - 같은 파일 어떤 코드에서도 접근 가능
  • private - 같은 파일 내부에 다른 타입 코드가 있어도 접근 불가능

private는 같은 파일에도 접근이 불가능 하지만 Extension 코드가 같은 파일에 존재하는 경에는 접근 가능하다.

public struct SomeType {
    private var privateProperty: Int = 0
    fileprivate var fileprivateProperty: Int = 0
}

//같은 extensiondptjsms private 요소 접근 가능
extension SomeType {
    public func publicMethod() {
        print("\(self.privateProperty), \(self.fileprivateProperty)")
    }
    private func privateMethod() {
        print("\(self.privateProperty), \(self.fileprivateProperty)")
    }
    fileprivate func fileprivateMethod() {
        print("\(self.privateProperty), \(self.fileprivateProperty)")
    }
}

struct AnotherType {
    var someInstance: SomeType = SomeType()
    
    mutating func someMethod() {
        //public 접근 수준은 어디서든 접근 가능
        self.someInstance.publicMethod()
        
        //fileprivate 접근수준은 같은 파일에 속해 있는 코드면 접근 가능
        self.someInstance.fileprivateProperty = 2
        self.someInstance.fileprivateMethod()
        
        //error: 다른 타입 내부의 코드 이므로 private 요소 접근 불가
        self.someInstance.privateProperty = 1
        self.someInstance.privateMethod()
    }
}

var anotherInstance = AnotherType()
anotherInstance.someMethod()

 

읽어주셔서 감사합니다 🤟

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.