티스토리 뷰
안녕하세요 :) Zedd입니다.
오늘은 Access Control..Swift4에서 정말 조그마한 변경사항이 있기도 했고..그래서 전체적으로 볼려고 합니다 :)
오랜만의 Swift네요 XD 모든 내용은 The Swift Programming Language (Swift 4.0.3)를 번역하는 수준이 될 거지만, 좋은 예제가 있다면 추가하도록 할게요 :)
Access Control(접근 제어)
Access Control(접근 제어)는 다른 소스파일 및 모듈의 코드에서, 코드의 일부에 대한 액세스(접근)을 제한합니다. 이 기능을 사용하면, 코드의 구현 세부사항을 숨기고, 해당 코드를 접근하고 사용 할 수 있는 기본 인터페이스를 지정 할 수 있습니다.
개별 타입(individual types)(클래스, 구조체 및 열거) 뿐만아니라, 해당 타입에 속하는 프로퍼티, 메소드, 이니셜라이저 및 첨자(subscripts)에 대해 특정 접근 레벨을 지정 할 수 있습니다.
프로토콜은 전역 상수, 변수 및 함수처럼 특정 컨텍스트로 제한 될 수 있습니다.
Swift는 다양한 수준의 접근 제어 외에도 일반적인 시나리오에 대한 기본 접근 수준을 제공함으로써, 명시적 접근 제어 수준을 지정할 필요성을 줄여줍니다.
사실, 단일 타겟 App을 작성하는 경우, 명시적 접근 제어 수준을 지정하지 않아도 됩니다.
Note : 접근 제어를 적용할 수 있는 코드의 다양한 측면( 프로퍼티, 타입, 함수 등)을 간결하게 하기 위해 아래에서 "엔티티"라고 언급하겠습니다.
자..아직 무슨말인지 하나도 이해를 못하실텐데요. 괜찮습니다.
객체지향을 배워보신 분들이라면 "은닉화"라는 말을 한번쯤은 들어보셨을거에요.
은닉화란 객체 외부에서 객체내의 자료로의 접근을 제한하고 데이터를 수정,조작하는 동작은 내부에 두고 접근(getter),설정(setter)하는 메소드로 결과만 받는것이다.
외부에서는 내부적인 움직임을 알수가 없으며 데이터에 어떤값이 있는지 또는 어떤 변화가 일어나는지 알수없으며 단지 데이터의 접근을 메서드(setter , getter)를 통해 결과만 받을뿐이다.
이를 가능하게 해주는것이 접근지정자를 private로 만들어줘서...블라블라
아무튼 이런말 한번쯤은 들어보셨을거에요 :)
이거랑 똑같아요! Swift의 접근제어가 이런 은닉화를 가능하게 해준답니다.
"Access Control(접근 제어)는 다른 소스파일 및 모듈의 코드에서, 코드의 일부에 대한 액세스(접근)을 제한합니다."
이 말은 굉장히 어렵게 보일 수도 있지만 그냥 간단한 말이에요. 접근을 제한해주는 것이죠.
1) 개별 타입(individual types)(클래스, 구조체 및 열거) 뿐만아니라, 2) 해당 타입에 속하는 프로퍼티, 메소드, 이니셜라이저 및 첨자(subscripts)에 대해 특정 접근 레벨을 지정 할 수 있습니다.
이 말은..뒤에서 나올거지만, 개별 타입이라함은 클래스, 구조체, 열거형이 있죠? 이 앞에 특정 접근레벨을 지정할 수 있다는 말입니다.
public class SomeClass{}
public struct SomeStruct {}
public enum SomeEnum {}
public class SomeClass{
fileprivate var someProperty : String = "Zedd"
private func someFunction() {}
}
Modules and Source Files
import Alamofire
Access Levels
이렇게 해줄게요. 하나는 클래스를 open으로 만들었고, 하나는 public으로 만들었네요. public init은 일단!! 무시해주세요. 나중에 왜 public이라고 썼는지 같이 봅시다.
그리고 이 Framework를 import해주고,
이렇게 해줬습니다. 여기까지는 아무 문제가 없어요. 왜냐?
open과 public은 어떠한 모듈이든 클래스와 클래스 멤버에 접근할 수 있기 때문이죠.
ZeddFramework는 외부 모듈이죠? 하지만, OpenClass와 PublicClass는 각각 open과 public으로 접근레벨이 지정되었기 때문에 여기서도 접근이 가능한것이죠.
import만 제대로 해줬으면요!
그럼 둘 차이가 도대체 뭐라는 걸까요..
위에서 언급했듯이 서브클래싱과 override인데요, 해봅시다.
import ZeddFramework
class SubClass : OpenClass {} //OK
자..제가 만든건 클래스니까 상속의 여지가 있겠죠? 그래서 접근 수준이 open이었던 OpenClass를 상속받는 SubClass를 만들어줬어요. SubClass앞에는 아무 접근 지정자를 붙히진 않았지만, 음..그래도 붙어있는 상태에요. 이 말은 나중에 하겠습니다.
Open은 (모듈) 어디서든 서브클래싱이 가능이라고 그랬죠?
SubClass라는 클래스에서 OpenClass를 상속받는게 가능합니다. 즉, OpenClass의 서브클래싱이 가능한거죠.
그러ㄴ ㅏ...
import ZeddFramework
class SubClass : PublicClass {} //Error!
open class OpenClass {
public init() {}
open func someMethod() {}
}
public class PublicClass{
public init() {}
public func someMethod() {}
}
자...someMethod는 클래스 멤버죠? 이 클래스 멤버에 open과 public 접근수준을 줘봤어요.
ZeddFramework외부.
import ZeddFramework
class A : OpenClass{
override func someMethod(){
print("Hello, world!")
}
}
open이었던 someMethod를 override키워드를 통해 잘 override를 한 것을 볼 수 있습니다.
하지만...지금은 ZeddFramework외부니까 publicClass는 상속조차...안됨........
그럼 상속이 되는 openClass에 someMethod()접근 수준을 public으로 하면 어떻게 될까요?
그러니까
open class OpenClass {
public init() {}
public func someMethod() {}
}
이렇게해주는거죠. 그러면...!!!
ZeddFramework외부.
import ZeddFramework
class A : OpenClass{
override func someMethod(){
print("Hello, world!")//Error!
}
}
아까는 잘되던 위 코드가 에러가 나게 됩니다.
open이 아닌건...외부에서...override할 수 없어..........
ㅇㅋ...
그럼 ZeddFramework내부에서는 잘 될까요?
지금 OpenClass의 someMethod의 접근수준이 public인데도!!! ZeddFramework내부에서는 잘되네요.
open은 당연히 되겠죠? 여기서도?
서브클래싱과 마찬가지로, override도 public만 안되는것이 아니라, 더 제한적인 접근수준들도 안됩니다.(외부모듈에서)
"public접근 권한이 있는 클래스 멤버 또는 제한적인 접근 수준은 정의 된 모듈 내에서만 하위 클래스에 의해 override 될 수 있습니다."
그러니까 총 정리하면
open : class, class 멤버는 정의된 모듈 내에서나, 그 모듈을 import하는 외부 모듈에서나 서브클래싱이나 override가 잘 된다"
public, internal, File-private, private : class, class멤버는 정의된 모듈 내에서만 서브클래싱이나 override가 된다"
인거죠 :)
open과 public의 차이점을 조금 아시겠나요?
이제 위에서 언급한
"클래스를 명시적으로 open으로 표시하면, 해당 클래스를 Super Class로 사용하는 다른 모듈에서 가져온 코드의 영향을 고려했으므로, 클래스 코드를 적절하게 디자인했음을 나타냅니다. "
가 무슨의미인지 알겠죠 XD?
자...5개의 접근수준이 있는데...지금 딱 2개봤어요. open과 public.
이제 나머지것들을 봐봅시다.
internal
internal은 위에서
"internal 접근은 엔티티가 정의 모듈의 모든 소스 파일 내에서 사용되지만, 해당 모듈 외부의 소스파일에서는 사용되지 않도록 합니다. 일반적으로 App이나 Framework의 내부 구조를 정의할 때 internal 접근을 사용합니다. "
천천히 읽으시면 이해가 잘 가실겁니다.
"정의 모듈의 모든 소스 파일 내에서 사용되지만, 해당 모듈 외부의 소스파일에서는 사용되지 않도록 합니다."
아 그러니까 internal로 표시된거는 모듈의 모든 소스파일에서는 접근이 가능하지만, 모듈의 외부에서는 사용되지 않도록 하는 접근지정자구나..
그러니까 한마디로 모듈 내에서만 사용할 수 있는거죠.
만약내가 ZeddFramework안에서
internal class InternalClass{
public init() {}
}
이렇게 해놨으면,
ZeddFramework밖에서 이렇게 하려고 하면..오류가 난다는 겁니다.
internal은 오직 정의된 모듈 안에서만 사용하자!!!라는 의미의 접근지정자에요.
사실 internal에서 가장 중요한 사실...은!!!
기본적인 접근수준이 바로 다 internal이라는 것이죠!!!!!!!!!!!!!!!!!!!!!!!!!!!
class SomeClass{
public init() {}
}
우리가 이렇게 써도.. 앞에는 internal이 붙어있는것이죠. 아시겠나요? internal은 기본 접근 수준이다!!라는 것을 꼭 기억해주세요.
internal은 일단 외부 모듈로 못나가니....모두 내부에서 사용될텐데..
여기서 퀴즈
internal class는 서브클래싱이 된다? internal class멤버는 override된다??
ㅇㅇ 다 된다.
그렇다면 여기서 또 퀴즈
만약 open접근수준인 class에서 internal class 멤버가 있으면? 외부에서 호출가능할까요?
네..불가능하죠.
open class OpenClass {
public init() {}
func someMethod() {}
}
someMethod()앞에 아무것도 없지만..기본 접근 수준이 뭐라고 그랬죠? 네 internal.
일단 class자체는 open수준이니, OpenClass타입의 인스턴스는 ZeddFramework외부에서 만들어질 수 있습니다.
하지만 그 인스턴스를 통해 someMethod로 접근이 가능할까요? 넵 불가능합니다.
이제 internal이 어떤 접근수준인지 조금 아시겠나요?!
자 다음 File-private으로 갑시다.
위에서
"File-private 접근은 자체 정의 소스 파일에 대한 엔티티 사용을 제한합니다. File-private접근을 사용하면 해당 세부 정보가 전체 파일 내에서 사용 될 때 특정 기능의 구현 세부 정보를 숨길 수 있습니다."
디게 어렵게 말을 써놨는데,..한마디로 이야기하면, 정의 소스 파일 내에서만 사용이 가능하다..라는 말입니다.
아까는 모듈 수준으로 막 사용이 가능하다₩~그랬는데 범위가 소스파일까지 내려왔네요.
그러니까, 외부 모듈에서 사용할 수 없는건 물론이고, 같은 모듈 내에서도 같은 소스파일 안에서만!!! 사용이 가능하다 이소리죠.
예를 봅시다. 이제부터 모두 ZeddFramework안에서 돌리는 코드들이라고 생각하시면 됩니다.
만약에 내가 이렇게 정의하고,
fileprivate class FileprivateClass{
public init() {}
}
위 클래스를 다른 파일에서 접근해볼게요.
이러면 오류가 나게 됩니다.File-private은 같은 모듈이어도 다른 소스파일이면 접근이 안되는거죠. 오직 그 File-private을 정의한 소스파일내에서만 사용이 가능합니다.
(위 internal에서 언급은 안했지만, internal은 당연하게도 같은 모듈내에서 다른 소스파일이어도 접근이 가능합니다. 한 모듈 내에서라면 어디서든지 접근이 가능하다고 보시면 됩니다.)
그럼 같은 파일 내에서 접근해봅시다.
fileprivate class FileprivateClass{
public init() {}
}
var fileprivateInstance = FileprivateClass()
자..이러면 될 것 같지만 오류가 하나 뜹니다.
이 변수(상수도 마찬가지)는 타입의 접근수준이 File-private이기때문에 private나 fileprivate로 선언이 되어야 한다고 에러가 나오네요.
fileprivate class FileprivateClass{
public init() {}
}
private var fileprivateInstance = FileprivateClass()
이렇게 해야만 비로소 잘 동작합니다.
서브클래싱도 당연히 같은 모듈, 같은 소스파일안에서만 가능하며, 그냥
fileprivate class FileprivateClass{
public init() {}
}
class A : FileprivateClass {} //Error!
이렇게 할려고 하면 에러가 나게 됩니다. 이유는 위와 거의 동일한데요, A의 Super Class의 접근 수준이 File-privated이니, 클래스 A도 private이나 fileprivate접근수준을 가져야한다는거죠.
fileprivate class FileprivateClass{
public init() {}
}
private class A : FileprivateClass {}
이렇게요.
override할때는 아무것도 안붙혀도 잘 된답니다 :)
open class OpenClass {
fileprivate func someMethod() {}
}
class A : OpenClass{
override func someMethod() {
print("Hello")
}
}
자..그럼 마지막 private XD
private는 Swift4에서 조금 변화가 있었는데요,
일단 그건 나중에보고..private가 뭔지 알아봅시다. 5개의 접근수준중 가장 제한적인데..얼마나 그럴지 봅시다.
private접근은 엔티티의 사용을 enclosing 선언과 동일한 파일에 있는 해당 선언의 extension으로 제한합니다. private접근을 사용하면 단일 정의 내에서만 사용되는 특정 기능 조각의 구현 상세 내역을 숨길 수 있습니다.
예제를 봅시다.
private class PrivateClass{
public init() {}
}
private let someInstance = PrivateClass() //OK
이런 클래스 인스턴스는 잘 만들어집니다. ==> init이 public이니까...init이 private면 인스턴스도 만들어지지 않습니다. fileprivate면 만들어지긴함.
(클래스 프로퍼티에 접근하기 위해서 init을 public으로 만드는거에요!)
하지만 프로퍼티나 메소드는...
private class PrivateClass{
public init() {}
private var name = "Zedd"
}
class Test {
private let someInstance = PrivateClass()
func someMethod(){
print(someInstance.name) //Error!
}
}
이렇게 Class안에서 안하면 top level 에러가 나서 ㅠㅠ 아무튼 저기 PrivateClass의 프로퍼티인, 그것도 접근 수준이 private인 name이라는 프로퍼티는!!! private기 때문에 이렇게 정의 밖에서 접근을 하지 못합니다.
(" 'name' is inaccessible due to 'private' protection level ")
그래서 Swift3에서는 private접근 수준은 "allows use only from the enclosing declaration"이게 다였는데..!!Swift4에서 조금 바뀌게 됩니다.
바로
"private접근은 엔티티의 사용을 enclosing 선언(enclosing declaration)과 동일한 파일에 있는 해당 선언의 extension으로 제한합니다."
이것이죠.
원래는
private class PrivateClass{
public init() {}
private var name = "Zedd"
}
extension PrivateClass{
func someMethod(){
print(name)//OK
}
}
이렇게 하면!!!!!!!!!!!!!!Swift3에서는 오류가 났는데 Swift4부터 접근이 가능해지게 됩니다.
하지만 반드시 같은 소스파일안에서의 extension만 가능하다는 것을 잊지마세요.
이것도 Swift4에서만 가능하다는 것도 잊지마세요...
private도 File-private와 마찬가지로 앞에 private나 fileprivate로 접근수준을 지정해줘야만 상속이 가능합니다.
fileprivate class A :PrivateClass {}
이렇게요. 하지만 override가 안됨
open class OpenClass {
private func someMethod() {}
}
class A : OpenClass{
override func someMethod() {}//Error!
}
이렇게요.
일단 5개의 접근수준이 뭐다!!!이런 느낌이다!!!라는 것만 봤어요 :) 예제 만드느라 거의 번역을 못했는데...다음글에서 The Swift Programming Language (Swift 4.0.3)에 나와있는 내용을 볼 것입니댜. 꼭 알아야 하는 내용이 많아서요!!!
오늘도 도움이 되었으면 좋겠어요 :)
혹시 틀린부분이나 지적할 부분이 있다면 꼭!! 댓글이나 PC화면 오른쪽 하단의 채널 서비스를 이용해주세요 :)
출처 : https://beerntv.wordpress.com/2017/01/18/0118-추상화-캡슐화-은닉/
https://medium.com/@abhimuralidharan/swift-3-0-1-access-control-9e71d641a56c
https://useyourloaf.com/blog/swift-4-access-levels/
'Swift' 카테고리의 다른 글
Swift ) Sequences와 Lazy (2) | 2018.01.16 |
---|---|
Swift ) Inheritance(상속) (7) | 2018.01.15 |
Swift ) 왕초보를 위한 Codable / JSON Encoding and Decoding (9) | 2018.01.06 |
Swift4 ) Swap / Law of Exclusivity (0) | 2017.12.21 |
Swift ) Protocols (4) (3) | 2017.12.17 |
- Git
- 스위프트
- Accessibility
- github
- swift 공부
- swift delegate
- 회고
- swift tutorial
- IOS
- swift sort
- 스위프트 문법
- 피아노
- SwiftUI
- fastlane
- np-hard
- actor
- Combine
- ios 13
- iOS delegate
- WWDC
- Swift
- WidgetKit
- UIBezierPath
- swift array
- 제이슨 파싱
- WKWebView
- Xcode
- np-complete
- FLUTTER
- swift3
- Total
- Today
- Yesterday