[Swift] 접근 제어

임승섭·2023년 7월 13일
0

Swift

목록 보기
27/35

접근 제어

  • 코드의 세부 구현 내용을 숨긴다 은닉화
class SomeClass {
    private var name = "이름"      // 클래스 내부적으로만 사용하겠다고 제한 (외부에서 접근 불가)
    
    func nameChange(name: String) {
        if name == "길동" {
            return             // 어떤 로직을 넣을 수도 있음
        }
        self.name = name
    }
}
let object1 = SomeClass()
/*에러*/
// object1.name
// object1.name = "홍길동"	

5가지 접근 수준

  • open - 다른 모듈에서도 접근가능 / 상속 및 재정의도 가능 (제한 낮음)
    • 클래스에서 가장 넓은 범위
  • public - 다른 모듈에서도 접근가능 (상속/재정의 불가)
    • 구조체에서 가장 넓은 범위 (구조체는 어차피 상속/재정의 불가)
  • internal - 같은 모듈 내에서만 접근가능 (디폴트)
  • fileprivate - 같은 파일 내에서만 접근가능
  • private - 같은 scope내에서만 접근가능 (제한 높음)

모듈(module): 프레임워크, 라이브러리, 앱 등 import해서 사용할 수 있는 외부의 코드

기본 원칙

  • 타입은 타입을 사용하는 변수(속성)나 함수(메서드)보다 높은 수준으로 선언되어야 한다
// String 타입(구조체)을 타고 들어가보면, public으로 선언되어 있다
// 그래서 변수를 선언할 때 이거보다 같거나 낮게 선언해줘야 한다
// open var some: String = "접근가능"	// 에러
internal var some: String = "접근가능"	// 디폴트는 internal

func someFunction(a: Int) -> Bool {	// 얘도 기본적으로 internal
	print(a)
    return true
}

기본 문법

// 타입
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}


// 변수 / 함수
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}


// 아무것도 붙이지 않으면?
class SomeInternalClass1 {}         // 암시적인 internal 선언
let someInternalConstant1 = 0

관습적인 패턴

// 언더바 붙인다 -> private
class SomeOtherClass {
	private var _name = "이름"		// 쓰기 - private
    
    var name: String {				// 읽기 - internal
    	return _name
    }
}

// 외부에서 쓰기 제한하기
class SomeAnotherClass {
	private(set) var name = "이름"	// 읽기 - internal, 쓰기 - private
}

커스텀 타입의 접근 제어

  • 타입의 내부 멤버는 타입 자체의 접근 수준을 넘을 수 없다
  • 타입이 internal로 선언되면 내부 멤버는 internal 이하만 가능
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"
}
  • 타입을 private으로 선언하는 것은 의미가 없다 -> fileprivate으로 동작한다
private class SomePrivateClass {                    // 명시적인 private 선언
    open var someOpenProperty = "SomeOpen"
    public var somePublicProperty = "SomePublic"
    var someInternalProperty = "SomeInternal"
    var someFilePrivateProperty = "SomeFilePrivate"     // 실제 fileprivate 처럼 동작 ⭐️ (공식문서 오류)
    private var somePrivateProperty = "SomePrivate"
}
  • 내부 멤버가 명시적 선언을 하지 않으면, 접근 수준은 internal로 유지
  • 타입의 접근 수준을 따라가는 건 아님!!
open class SomeClass {
	var someProperty = "SomeInternal"	// 디폴트 internal로 유지
}

상속과 확장의 접근 제어

상속

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

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

확장

  • 기본 : 원래 본체와 동일한 접근 수준 유지하고, 본체 멤버에는 기본적인 접근 가능
public class SomeClass {
	private var somePrivateProperty = "somePrivate"
}

extension SomeClass {	// public으로 선언한 것과 동일
	func somePrivateControlFunction() {
    	somePrivateProperty = "접근 가능"
    }
}

속성의 접근 제어

  • 변수 및 속성, 서브스크립트에 쓰기 수준을 읽기 수준보다 낮은 접근 수준으로 설정 가능
  • 쓰기의 수준이 더 높은 건 불가능하다
// 일반적으로 밖에서 쓰는 것(setter)은 불가능하도록 구현하는 경우가 많음

struct TrackedString {
    //var numberOfEdits = 0                   // 외부에서도 변경가능
    //private var numberOfEdits = 0           // 이렇게 선언하면, 읽기도 불가능해짐
    private(set) var numberOfEdits = 0        // setter에 대해서만 private 선언 ⭐️
    // 읽기 : 자동 설정 internal 수준
    // 쓰기 : private 수준
    //internal private(set) var numberOfEdits = 0
    
    // 속성 관찰자
    var value: String = "시작" {
        didSet {
            numberOfEdits += 1
        }
    }
}

0개의 댓글