일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Python
- iOS앱배포
- 계산기앱만들기
- AJAX
- 자바스크립트
- Xib
- 딩동말씀
- Swift
- 스프링
- customclass
- 앱배포
- iOS계산기
- FLASK
- JavaScript
- 개발기록
- jQuery
- DispatchGroup
- 스위프트
- 앱버전구하기
- 파이썬서버
- subscript
- 계산기앱
- ios
- iOS배포
- 웹
- MainScheduler
- 맥
- FileOwner
- Xcode
- spring
- Today
- Total
개발하는 뚝딱이
[swift] 접근제어 본문
책 <스위프트 프로그래밍 3판 ;야곰 지음> 을 정리한 글입니다.
1. 접근제어
- 접근제어 ; 코드끼리 상호작용을 할 때 파일 간 또는 모듈 간에 접근을 제한할 수 있는 기능
- 객체지향 패러다임의 Hiding (은닉화) 개념 중 하나
- 접근제어를 통해 코드의 상세구현은 숨기고 허용된 기능만 사용하는 인터페이스를 제공
1.1-1 접근제어의 필요성
- 불필요한 접근으로 의도치 않은 결과를 초래하거나 꼭 필요한 부분만 제공을 해야하는데 전체 코드가 노출될 가능성이 있을 때 접근제어를 이용
1.1-2 모듈과 소스파일
- 모듈 (Module) : 배포할 코드의 묶음 단위. 하나의 프레임워크나 라이브러리 또는 애플리케이션이 모듈 단위가 될 수 있음. 스위프트에서는 import 키워드를 사용하여 불러움
- 소스파일 : 하나의 스위프트 소스 코드 파일. 보통 파일 하나에 타입 하나를 정의하지만 때로는 소스파일 하나에 여러 타입이나 함수 등 많은 것을 정의하거나 구현 가능
2. 접근수준
- 접근제어는 접근수준 (Access Level) 키워드를 통해 구현
- 각 타입 (클래스, 구조체, 열거형 등)에 접근수준을 지정하고 타입 내부의 프로퍼티, 메서드, 이니셜라이저, 서브스크립트 각각에도 접근수준을 지정할 수 있음
접근수준 | 키워드 | 접근도 | 범위 | 비고 |
개방 | open | 높음 | 모듈 외부까지 | 클래스에서만 사용 |
공개 | public |
↑ ↓ |
모듈 외부까지 | |
내부 | internal | 모듈 내부 | ||
파일외부비공개 | fileprivate | 파일 내부 | ||
비공개 | private | 낮음 | 기능 정의 내부 |
2.1 공개 접근 수준 (Public)
- public 키워드로 접근수준이 지정된 요소는 어디서든 쓰일 수 있음
- 자신이 구현된 소스 파일, 소스파일이 속해 있는 모듈, 그 모듈을 가져다 쓰는 모듈 등
- 공개(Public) 접근수준은 주로 프레임워크에서 외부와 연결될 인터페이스를 구현하는데 많이 사용됨
- 우리가 사용하는 스위프트의 기본 요스는 모두 공개 수준으로 구현되어 있음
// 스위프트 표준 라이브러리에 정의되어 있는 Bool 타입
/// A value type whose instances are 'true' or 'false
public struct Bool {
/// Default-initialize Boolean value to 'false'
public init()
}
2.2 개방 접근 수준 (open)
- 클래스와 클래스의 멤버에서만 사용 가능
- 클래스를 개방 접근 수준으로 명시한 것은, 그 클래스를 다른 모듈에서도 부모 클래스로 사용하겠다는 목적으로 클래스를 설계하고 코드를 작성했다는 의미
- 공개 (public) 접근 수준과 비슷하지만 아래의 차이점이 있음
- 개방 접근 수준을 제외한 다른 모든 접근수준의 클래스는 그 클래스가 정의된 모듈 안에서만 상속 가능
- 개방 접근 수준을 제외한 다른 모든 접근수준의 클래스 멤버는 해당 멤버가 정의된 모듈 안에서만 재정의할 수 있음
- 개방 접근 수준의 클래스는 그 클래스가 정의된 모듈 밖의 다른 모듈에서도 상속 가능
- 개방 접근 수준의 클래스 멤버는 해당 멤버가 정의된 모듈 밖의 다른 모듈에서도 정의 가능
// Foundation 프레임워크에 정의되어 있는 개방수준의 NSString 클래스
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)
}
2.3 내부 접근 수준 (internal)
- 기본적으로 모든 요소에 암묵적으로 지정하는 기본 접근 수준
- 소스파일이 속해 있는 모듈 어디에서든 쓰일 수 잇음
- 그러나 그 모듈을 가져다 쓰는 외부 모듈에서는 접근 불가
- 보통 외부에서 사용할 클래스나 구조체가 아니며, 모듈 내부에서 광역적으로 사용할 경우 내부 접근수준을 지정
2.4 파일외부 비공개 접근 수준 (fileprivate)
- 그 요소가 구현된 소스파일 내부에서만 사용가능
- 해당 소스파일 외부에서 값이 변경되거나 함수를 호출하면 부작용이 생길 때 사용하면 좋음
2.5 비공개 접근 수준 (private)
- 그 기능을 정의하고 구현한 범위 내에서만 사용
- 비공개 접근 수준으로 지정한 기능은 심지어 같은 소스파일 내에 구현한 다른 타입이나 기능에서도 사용 불가능
3. 접근제어 구현
- internal의 경우 안적어줘도 됨
open class OpenClass {
open var openProperty: Int = 0
public var publicProperty: Int = 0
internal var internalProperty: Int = 0
private var privateProperty: Int = 0
open func openMethod() {}
public func publicMethod() {}
internal func internalMethod() {}
fileprivate func fileprivateMethod() {}
private func privateMethod() {}
}
public class PublicClass {}
public struct PublicStruct {}
public enum PublicEnum {}
public var publicVariable = 0
public let publicConstant = 0
public func publicFunction() {}
internal class InternalClass {}
internal struct InternalStruct {}
internal var internalVariable = 0
internal let internalConstant = 0
internal func internalFunction() {}
fileprivate class FilePrivateClass {}
fileprivate struct FilePrivateStruct {}
fileprivate enum FilePrivateEnum {}
fileprivate var filePrivateVariable = 0
fileprivate let filePrivateConstant = 0
fileprivate func filePrivateFunction() {}
private class PrivateClass {}
private struct PrivateStruct {}
private enum PrivateEnum {}
private var privateVariable = 0
private let privateConstant = 0
private func privateFunction() {}
4. 접근제어 구현 참고사항
- '상위 요소보다 하위 요소가 더 높은 수준을 가질 수 없다'
// 잘못된 접근수준 부여
private class AClass {
// 공개 접근수준을 보여해도 AClass의 접근수준이 비공개이므로
// 이 메서드의 접근수준도 비공개 접근수준으로 취급
public func someMethod() {
// ...
}
}
// AClass의 접근수준이 비공개 접근수준이므로
// 공개 접근수준 함수의 매개변수나 반환 값 타입으로 사용할 수 없음
public func someFunction(a: AClass) -> AClass {
return a
}
- 튜플의 내부 요소 타입이 튜플의 접근 수준보다 같거나 높아야 함
internal class InternalClass {} // 내부 접근수준 클래스
private struct PrivateStruct {} // 비공개 접근수준 구조체
// 요소로 사용되는 InternalCalss와 PrivateStruct의 접근수준이
// publicTuple보다 낮기 때문에 사용할 수 없음
public var publicTuple: (first: InternalClass, second: PrivateStruct) = (InternalClass(), PrivateStruct())
// 요소로 사용되는 InternalClass와 PrivateStruct의 접근수준이
// privateTuple과 같거나 높기 때문에 사용할 수 있음
private var privateTuple: (first: InternalClass, second: PrivateStruct) = (InternalClass(), PrivateStruct())
- 접근수준에 따른 접근 결과
- 프레임워크를 만들 때는 다른 모듈에서 특정 기능에 접근할 수 있도록 public 공개 접근 수준으로 지정해야 함
// AClass.swift 파일과 Common.swift 파일이 같은 모듈에 속해 있는 경우
// AClass.swift 파일
class AClass {
func internalMethod() {}
fileprivate func filePrivateMethod() {}
var internalProperty = 0
fileprivate var filePrivateProperty = 0
}
// Common.swift 파일
let aInstance: AClass = AClass()
aInstance.internalMethod() // 같은 모듈이므로 호출 가능
aInstance.filePrivateMethod() // 다른 파일이므로 호출 불가 - 오류
aInstance.internalProperty = 1 // 같은 모듈이므로 접근 가능
aInstance.filePrivateProperty = 1 // 다른 파일이므로 접근 불가 - 오류
- 각 case의 접근수준은 열거형 자체의 접근수준
- 열거형의 원시 값 타입으로 열거형의 수준보다 낮은 접근수준의 타입이 올 수 없음
private typealias PointValue = Int
// 오류 - PointValue가 Point보다 접근수준이 낮기 때문에 원시값으로 사용 불가
enum Point: PointValue {
case x, y
}
5. private와 fileprivate
- fileprivate 접근수준으로 지정한 요소는 같은 파일 어떤 코드에서도 접근이 가능
- private 접근수준으로 지정한 요소는 같은 파일 내부에 다른 타입의 코드가 있더라도 접근이 불가능
- 그러나 자신을 확장하는 익스텐션 코드가 같은 파일에 존재하는 경우 접근 가능
public struct SomeType {
private var privateVariable = 0
fileprivate var fileprivateVariable = 0
}
// 같은 타입의 익스텐션에서는 private 요소에 접근 가능
extension SomeType {
public func publicMethod() {
print("\(self.privateVariable), \(self.fileprivateVariable)")
}
fileprivate func fileprivateMethod() {
print("\(self.privateVariable), \(self.fileprivateVariable)")
}
private func privateMethod() {
print("\(self.privateVariable), \(self.fileprivateVariable)")
}
}
struct AnotherType {
var someInstance: SomeType = SomeType()
mutating func someMethod() {
// public 접근수준에는 어디서든 접근 가능
self.someInstance.publicMethod() // 0, 0
// 같은 파일에 속해 있는 코드이므로 fileprivate 접근 수준 요소에 접근 가능
self.someInstance.fileprivateVariable = 100
self.someInstance.fileprivateMethod() // 0, 100
// 다른 타입 내부의 코드이므로 private 요소에 접근 불가! 오류!
// self.someInstance.privateVariable = 100
// self.someInstance.privateMethod()
}
}
var anotherInstance = AnotherType()
anotherInstance.someMethod()
6. 읽기 전용 구현
public struct SomeType {
// private 저장 프로퍼티
private var count: Int = 0
// public 저장 프로퍼티
public var publicStoredProperty: Int = 0
// public 저장 프로퍼티
// setter는 private
public private(set) var publicGetOnlyStoredProperty: Int = 0
// internal 연산 프로퍼티
internal var internalComputedProperty: Int {
get {
return count
}
set(newValue) {
count += newValue
}
}
// internal 연산 프로퍼티
// setter는 private
internal private(set) var internalGetOnlyComputedProperty: Int {
get {
return count
}
set {
count += 1
}
}
// public 서브스크립트
public subscript() -> Int {
get {
return count
}
set {
count += 1
}
}
// public 서브스크립트
// setter는 internal
public internal(set) subscript(some: Int) -> Int {
get {
return count
}
set {
count += 1
}
}
}
var someInstance: SomeType = SomeType()
// 외부에서 접근자, 설정자 모두 사용 가능
someInstance.publicStoredProperty = 10
print(someInstance.publicStoredProperty) // 10
//someInstance.publicGetOnlyStoredProperty = 10 // 오류 발생
print(someInstance.publicGetOnlyStoredProperty) // 0
someInstance.internalComputedProperty = 10
print(someInstance.internalComputedProperty) // 10
//someInstance.internalGetOnlyComputedProperty = 10 // 오류 발생
print(someInstance.internalGetOnlyComputedProperty) // 1
// 외부에서 접근자, 설정자 모두 사용 가능
print(someInstance[]) // 10
someInstance[] = 100
// 외부에서 접근자만, 같은 모듈 내에서는 설정자도 사용 가능
print(someInstance[0]) // 11
someInstance[0] = 100
'swift' 카테고리의 다른 글
[swift] 옵셔널 체이닝과 빠른 종료 (0) | 2020.05.08 |
---|---|
[swift] 클로저 (0) | 2020.05.07 |
[swift] 인스턴스 생성 및 소멸 (0) | 2020.05.01 |
[swift] 옵셔널 (0) | 2020.04.28 |
[swift] 메소드 (method) (0) | 2020.04.27 |