본문 바로가기

Swift

mac OS #Framework 생성, Cannot find #FUNCTION in scope error, Swift #접근제어자 와 @testable

반응형

2021/01/20 - [Swift] - #Postman 이용하여 #대부분의 데이터를 받아오는 방법!

 

#Postman 이용하여 #대부분의 데이터를 받아오는 방법!

이미 존재하는 서비스를 활용하여 만드는 경우, 해당 서비스가 사용하는 (그러나 개인에게는 제공되지 않는) API를 활용하여 데이터를 받아와야 하는 경우가 생깁니다. 그리고 절차를 밟지 않고

roomedia.tistory.com

어제 다음과 같이 Papago 번역 API를 호출하는 기능을 만든 뒤, 제대로 작동하는지 확인하기 위해 테스트 해보았습니다. 먼저, 번역 기능은 여러 개의 Target에서 사용될 함수이기 때문에 Framework를 하나 생성하여 해당 Framework로 이동시켰습니다. XCode Menu의 File > New > Target...을 누른 뒤, Framework를 추가해줍니다.

생성했던 SearchService.swift 파일을 해당 프레임워크 폴더로 옮겨주시고, File Inspector의 Target Membership에서 빌드 타겟을 해당 프레임워크만 체크해주세요. swift 파일의 경우! header 파일에 따로 추가해주지 않아도 사용할 수 있었습니다.

이제 공개할? 함수 빼고 나머지 함수, 구조체는 private 접근 제어자를 붙여 파일 내부에서만 사용할 수 있도록 만들었는데요. 여기서 몇 가지 놓치고 있던 개념을 발견했습니다! 저는 다음과 같이 접근 제어자를 붙이지 않은 함수는 public으로 지정되는 줄 알았답니다...

테스트 시에도 문제 없이 불러올 수 있어 괜찮을 줄 알았는데요. 막상 실제로 사용하려고 보니 Cannot find 'fetchTransalted' in scope 에러가 발생하며 빌드를 실패하는 겁니다....

여기에는 두 가지 문제가 숨어있는데요. 1. 접근 제어에 대한 지식이 부족했고, 2. @testable에 대한 개념이 부족했습니다.

접근 제어

Swift의 접근 제어 모델은 모듈 및 소스 파일을 대상으로 적용됩니다. 모듈은 코드를 배포하는 하나의 단위, 즉 프레임워크나 어플리케이션 같이 다른 모듈에 import 키워드를 사용하여 포함할 수 있는 코드의 단위를 말합니다. XCode는 각각의 빌드 타겟을 하나의 독립적인 모듈로 취급합니다.

소스 파일은 모듈 내에 존재하는 단일 스위프트 소스코드 파일을 말합니다. 하나의 파일에는 개별 타입을 정의하는 것이 일반적이지만, 한 소스파일에 다양한 타입, 함수 등이 존재할 수 있습니다.

Swift는 다섯 단계의 접근 제어 방식을 제공합니다. 위 접근 제어 단계는 소스 파일과 모듈에 연관되어 있습니다.

  • open과 public 접근 제어자가 지정된 타입, 함수 등은 자신이 정의된 모듈 내에서 자유롭게 사용될 수 있으며, 해당 모듈을 import한 다른 모듈의 소스파일에서도 사용될 수 있습니다. open은 가장 자유도가 높은 접근 제어 단계로, 클래스와 클래스 멤버에만 사용될 수 있으며, subclass와 override를 허용합니다. public 단계에서는 subclass와 override가 허용되지 않습니다.
  • internal 접근 제어자는 지정된 타입, 함수를 정의된 모듈 내에서 자유롭게 사용할 수 있도록 허용합니다. 해당 모듈 외부에서는 사용할 수 없으며, 일반적으로 앱과 프레임워크의 내부 구조체를 정의할 때 사용합니다.
  • fileprivate 접근 제어 레벨로 설정된 타입, 함수는 해당 소스파일을 벗어나 사용할 수 없습니다. fileprivate 접근 제어는 파일 전체에 걸쳐 사용되는 함수의 특정 부분 구현 사항을 드러내지 않기 위해 사용됩니다.
  • private 접근 제어자는 유일하게 사용되는 함수의 특정 부분 구현 사항을 외부에 드러내지 않기 위해 사용됩니다.

접근 제어자를 붙이지 않은 경우, 기본 설정은 internal입니다. 따라서 fetchTranslated 함수는 외부에서 사용하지 못하며, Cannot find 'fetchTranslated' in scope와 같은 에러가 발생하는 것입니다.

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 SomeInternalClass {}              // implicitly internal
let someInternalConstant = 0            // implicitly internal

public class SomePublicClass {                  // explicitly public class
    public var somePublicProperty = 0            // explicitly public class member
    var someInternalProperty = 0                 // implicitly internal class member
    fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}

class SomeInternalClass {                       // implicitly internal class
    var someInternalProperty = 0                 // implicitly internal class member
    fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}

fileprivate class SomeFilePrivateClass {        // explicitly file-private class
    func someFilePrivateMethod() {}              // implicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}

private class SomePrivateClass {                // explicitly private class
    func somePrivateMethod() {}                  // implicitly private class member
}

접근 제어에 대한 추가적인 설명과 영어 원문은 다음에서 확인하실 수 있습니다.

docs.swift.org/swift-book/LanguageGuide/AccessControl.html

 

Access Control — The Swift Programming Language (Swift 5.3)

Access Control Access control restricts access to parts of your code from code in other source files and modules. This feature enables you to hide the implementation details of your code, and to specify a preferred interface through which that code can be

docs.swift.org

@testable

그런데 이상하지 않나요? Test 코드에서는 fetchTranslated가 internal인데도 불구하고 사용할 수 있었습니다. Test 코드는 Application 코드와 무엇이 다른 걸까요? Test 코드에서는 프레임워크를 @testable Attribute를 붙여 import 하는 것을 볼 수 있습니다.

관습적으로 붙였던 @testable Attribute는 사실 import에 붙여 사용했을 때 해당 모듈의 접근 제어 레벨을 바꾸는 역할을 합니다. internal로 명시된, 혹은 암시적으로 internal로 지정된, 접근 제어 레벨은 public 접근 제어자가 붙은 것처럼 변합니다. internal, public 접근 제어자가 붙은 클래스와 클래스 멤버는 open 접근 제어 레벨로 바뀝니다. @testable Attribute를 붙이기 위해서는 import 하려는 모듈이 반드시 컴파일 된 상태여야 합니다.

다음 문서에 위와 같은 설명이 짤막하게 한 토막 나와 있습니다.

docs.swift.org/swift-book/ReferenceManual/Attributes.html

 

Attributes — The Swift Programming Language (Swift 5.3)

Attributes There are two kinds of attributes in Swift—those that apply to declarations and those that apply to types. An attribute provides additional information about the declaration or type. For example, the discardableResult attribute on a function d

docs.swift.org

 

반응형