접근제한자
코드 요소에 대한 외부 접근을 제한하여
모듈 간의 접근성과 보안을 조절하는 접근 제한자에 대해
학습해 보려고 합니다.
접근 제한자는 다른 소스 파일이나 모듈의 코드에서 코드 일부에 대한 접근을 제한합니다.
open
모든 소스 파일에서 해당 level 접근 가능 + 모든 곳에서 서브클래싱 가능
public
모든 소스 파일에서 해당 level 접근 가능 + 같은 모듈 내에서만 서브클래싱 가능
internal
같은 모듈 내에서만 접근 가능
fileprivate
같은 소스파일 내에서만 접근 가능
private
클래스 내부에서만 접근 가능
접근 제한자를 작성하지 않으면 'internal'로 판단합니다
상위 요소보다 하위 요소가 더 높은 접근 수준을 가질 수 없습니다.
예시 코드
// 잘못된 형태
private struct Car {
public var model: String // 🚨 에러
}
// 상위는 하위보다 같거나 더 높은 접근 수준을 가져야 합니다.
모듈과 소스파일
모듈(module)
배포할 코드의 묶음 단위입니다.
하나의 프레임워크/ 라이브러리/ 어플리케이션이 모듈 단위가 될 수 있습니다.
import 키워드를 통해 불러올 수 있습니다.
소스파일
하나의 swift 소스 코드 파일을 의미합니다.
public, open
둘 다 모듈 외부까지 접근할 수 있습니다.
open
클래스와 클래스 맴버에서만 사용가능 하고 다른 모듈에서
서브클래싱이 가능하지만 public은 그렇지 않습니다.
open으로 클래스를 개방 접근 수준으로 명시하는 것은
그 클래스를 다른 모듈에서도 수퍼클래스로 사용하겠다는 의미로
해당 클래스를 설계하고 만들었다는 것을 의미합니다(다른 모듈에서 상속을 허용함)
public
주로 프레임워크에서 외부와 연결될 인터페이스를 구현하는데 많이 사용합니다.
internal
모든 요소에 암묵적으로 지정하는 디폴트 접근 제어자입니다.
소스 파일이 속해있는 모듈 어디에든 접근할 수 있지만 외부 모듈에서는 접근불가 입니다.
fileprivate
소스 파일 내부에서만 접근할 수 있습니다.
서로 다른 클래스가 같은 하나의 소스 파일에 정의되어있고
fileprivate로 선언되어 있다면 두 클래스는 서로 접근할 수 있습니다.
private
가장 제한적인 접근제어자입니다.
fileprivate과 달리 같은 파일 안에 있어도 서로 다른 클래스이고
private로 선언되어 있다면 두 요소는 서로 접근불가 입니다.
// open 예시
/*
open을 사용할 때에는 class나 func앞에 open이라는 키워드를 사용하면 됩니다.
그러면 접근제한자의 허용 범위가 적용이 되게 됩니다.
*/
open class Vehicle { // 상위 | 접근제어자 동일
open func startEngine() { // 하위 | 접근제어자 동일
print("Engine started")
}
}
open class Car: Vehicle { // 상위
open var carType: String = "Sedan" // 하위
/*
상위 하위 둘다 open으로 사용되는 것을 볼수 있는데 이러한 경우에도 가능합니다.
*/
}
// public - 모듈화에 필요
// public으로 프로퍼티에 접근제어자를 줄 수 있습니다.
// struct 앞에도 public이 가능합니다.
public struct Point { // x, y
public var x: Int // 내부의 public은 없어도 무관합니다.
public var y: Int
// 접근제어자의 수준이 상위,하위가 동일하여 이와 같이 사용이 가능합니다.
public init(x: Int, y: Int) {
self.x = x
self.y = y
}
// 함수에서도 public을 붙여주는 것이 가능합니다.
public mutating func moveByX(_ deltaX: Int, y deltaY: Int) {
self.x += deltaX
self.y += deltaY
}
/*
mutating 키워드 = struct와 비슷하게 값 타입에서 사용해야하는 키워드 입니다.
struct나 Enums 안에 있는 이 프로퍼티의 값을 변경할 때 mutating이라는 키워드를
반드시 사용 해주어야 합니다.
*/
}
// internal 키워드 = internal 자체를 작성 하지 않은것과 동일합니다. 즉, 일반적으로는 클래스만 작성하는 방식으로 그냥 단순히 var, func 이런식으로 정의를 해왔습니다. 굳이 써주고 싶다면 써도 되지만 사실상 필요는 없습니다. 그렇지만 알고는 있어야 하는 부분입니다.
internal class InternalClass {
internal var internalProperty: Int = 10
internal func doSomethingInternally() {
print("Internal operation performed")
}
}
internal let internalConstant = 20
// fileprivate (파일프라이빗)
/*
아래 예시에서는 내부 프로퍼티나 메서드에만 적용이 된것을 볼 수 있습니다.
특징으로는 클래스 내부에 또 클래스를 둘 수 있는데 이럴 경우에 fileprivate을 사용할 수 있습니다.
이유는 상위의 개념 OuterClass는 현재 internal(인터널)이 기본적으로 들어가 있는 상태이며,
fileprivate이 그보다 더 높은 접근제한을 가지고 있기 때문에 이러한 경우가 허용이 되는 것입니다.
*/
class OuterClass {
fileprivate var outerVariable = 30
fileprivate func outerFunction() {
print("Outer function called")
}
fileprivate class InnerClass {
fileprivate func innerFunction() {
print("Inner function called")
}
}
}
// private(프라이빗)
class MyClass { // 클래스 앞에는 internal(인터널)로 선언이 되어 있지만 만약 내부의 프로퍼티와 함수를 막고 싶을 경우 프라이빗 사용
private var privateVariable = 40
private func privateFunction() {
print("Private function called")
}
}
/*
Swift에서 mutating 키워드는 구조체(Structs)나 열거형(Enum) 내에서
메서드(Method)가 해당 구조체 또는 열거형의 속성을 수정할 수 있도록 하는 키워드입니다.
기본적으로 Swift에서는 구조체나 열거형의 인스턴스가 상수로 선언되면
해당 인스턴스의 속성을 변경할 수 없습니다.
그러나 메서드 내에서 해당 인스턴스의 속성을 변경하려면 mutating 키워드를 사용하여
해당 메서드가 해당 인스턴스의 속성을 수정할 수 있도록 허용해야 합니다.
*/
// 구조체 예시
struct Point {
var x = 0.0, y = 0.0
/*
x와 y의 값을 변경을 시키기 위해선 moveBy 라는 함수를 활용해서 이동을 시켜주는데
deltaX와 deltaY를 받아서 x, y에 각각 더해줄 수 있습니다. 그렇게 더해서 프로퍼티의 값이 변했을 때
mutating 키워드가 사용이 되어야 합니다. (클래스에서는 사용하지 않습니다)
*/
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var point = Point(x: 1.0, y: 1.0) // Point에 x 1.0 y 1.0 으로 초기화 하고
print("Before moving: x = \(point.x), y = \(point.y)") // 프린트하라..
point.moveBy(x: 2.0, y: 3.0) // moveBy를 호출하면 x와 y의 값이 더해졌으니 호출값도 달라지죠
print("After moving: x = \(point.x), y = \(point.y)")
// Before moving: x = 1.0, y = 1.0
// After moving: x = 3.0, y = 4.0
// 열거형 예시
/*
TrafficLight = 신호등 예시입니다.
신호등이 빨강 노랑 초록 있습니다.
next() 라는 함수도 보입니다.
빨간색일 경우 다음에 켜지는 신호등은 초록, 다음은 노랑, 다음은 빨강, 다음은 노랑의 순서를 나타내고 있습니다.
핵심은 self를 통해서 자신의 인스턴스 값을 바꾸고 있기 때문에 mutating 키워드를 반드시 사용해야합니다.
*/
enum TrafficLight {
case red, yellow, green
mutating func next() {
switch self {
case .red:
self = .green
case .yellow:
self = .red
case .green:
self = .yellow
}
}
}
var currentLight = TrafficLight.red // 현재 빨간색으로 설정
print("Current light is \(currentLight)") // 빨강 호출
currentLight.next()
print("Next light is \(currentLight)") // next를 호출 -> 초록
// Current light is red
// Next light is green
'IOS > Swift-Study' 카테고리의 다른 글
[Swift-Study] 심화 문법종합반 2주차 3일차 정리 - 고차함수 (0) | 2024.03.25 |
---|---|
[Swift-Study] 심화 문법종합반 2주차 2일차 정리 - 클로저 (0) | 2024.03.22 |
[Swift-Study] 심화 문법종합반 2주차 1일차 정리 - 타입 캐스팅 (0) | 2024.03.12 |
[Swift-Study] 심화 문법종합반 2주차 1일차 정리 - 프로퍼티 옵저버 (0) | 2024.03.12 |
[Swift-Study] 기초 문법종합반 1주차 4일차 정리 - 초기화 (0) | 2024.03.12 |