❓접근 제어가 왜 필요할까?
- 코드의 세부 구현 내용을 숨기는 것이 가능해짐(객체지향 - 은닉화⭐️)
- 속성, 메서드를 숨길 수 있음.
- 코드의 영역을 분리시켜서, 효율적 관리 가능
- 컴파일 시간이 줄어듬(컴파일러가 변수의 사용범위를 인지가능)⭐️
- 애플이 자신들이 원하는 코드를 감출 수 있음
❓접근 제어를 가질 수 있는 요소
스위프트 공식문서 ==> 엔티티/ 독립된 개체
- 타입(클래스/구조체/열거형/스위프트 기본타입 등)
- 변수/속성
- 함수/메서드(서브스크립트, 생성자 포함)
- 프로토콜도 특정 영역으로 제한될 수 있음
❓접근 수준(Access Levels)
1) open - 다른 모듈에서도 접근가능 / 상속 및 재정의도 가능 (제한 낮음)
2) public - 다른 모듈에서도 접근가능(상속/재정의불가)
3) internal - 같은 모듈 내에서만 접근가능(디폴트)
4) fileprivate - 같은 파일 내에서만 접근가능
5) private - 같은 scope내에서만 접근가능 (제한 높음)
- 클래스의 접근수준을 가장 넓히면 - open / 구조체 - public
- 1) 클래스 - open (상속, 재정의와 관계)
- 2) 구조체 - public (구조체는 어짜피 상속이 없기 때문)
- 모듈 : 배포할 코드의 묶음 단위
통상적으로 하나의 프레임워크나 라이브러리 또는 애플리케이션이 모듈 단위가 됨
스위프트에선 import 키워드를 사용해 불러옴 - 소스파일 : 하나의 스위프트 소스 코드 파일
자바나 Objective-C와 같은 기존의 프로그래밍 언어에서는 통상 파일 하나에 타입을 하나만 정의함
스위프트에서도 보통 파일 하나에 타입 하나만 정의하지만 때로는 소스파일 하나에 여러 타입이나 함수 등 많은 것을 정의하거나 구현할 수 있음
접근 수준을 선언하지 않으면 default = 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"
}
let somePublic = SomePublicClass()
somePublic.someOpenProperty
somePublic.somePublicProperty
somePublic.someInternalProperty
somePublic.someFilePrivateProperty // 같은 파일 안이기 때문에 접근 가능
//somePublic.somePrivateProperty //private이기 때문에 {}외부에서 접근 불가
클래스가 public이라고 명시되어 있기 때문에 내부의 멤버들은 open이 될 수 없다.
또한 fileprivate로 선언한 클래스를 internal로 선언할 수 없다.
하위로는 가능하지만 상위로는 불가능하다⭐️⭐️
타입을 private로 선언하면 아무곳에서도 사용할 수 없기 때문에 의미가 없다
타입을 private로 선언하면 fileprivate로 동작한다⭐️⭐️
ex)
private class SomePrivateClass{}
fileprivate let somePrivate = SomePrivateClass() //원래는 불가능하지만 이상황만 가능
상속과 확장의 접근제어
상속
- 1)타입 관련: 상속해서 만든 서브클래스는 상위클래스보다 더 높은 접근 수준을 가질 수는 없음
- 2)멤버 관련: 동일 모듈에서 정의한 클래스의 상위 멤버에 접근가능하면, (접근 수준 올려서) 재정의(override)도 가능
public class A {
fileprivate func someMethod() {}
}
// public이하의 접근 수준만 가능(public/internal/fileprivate)
internal class B: A {
override internal func someMethod() { // 접근 수준 올려서 재정의 가능 ⭐️
super.someMethod() // (더 낮아도) 모듈에서 접근가능하기 때문에 호출가능
}
}
확장
기본법칙 - 원래 본체와 동일한 접근 수준을 유지하고, 본체의 멤버에는 기본적인 접근 가능
public class SomeClass {
private var somePrivateProperty = "somePrivate"
}
extension SomeClass { // public으로 선언한 것과 같음
func somePrivateControlFunction() {
somePrivateProperty = "접근가능"
}
}
❗️실무에서 사용하는 관습적인 패턴⭐️⭐️
실제 프로젝트에서 많이 사용하는 관습적인 패턴!
속성(변수)를 선언 시 private으로 외부에 감추려는 속성은 _(언더바)를 사용해서 이름을 짓는다.
class SomeOtherClass {
private var _name = "이름" // 쓰기 - private
var name: String { // 읽기 - internal
return _name
}
}
저장속성의 (외부에서)쓰기를 제한하기⭐️⭐️⭐️
class SomeAnotherClass {
private(set) var name = "이름" // 읽기 - internal / 쓰기 - private
}
class SomeAnotherClass {
// 읽기 / 쓰기
public private(set) var name = "이름" // 읽기 - public / 쓰기 - private
}