본문 바로가기

iOS

SwiftGen

728x90

SwiftGen

프로젝트 리소스를 Swift 코드로 자동 생성하여 안전한 타입으로 사용 가능 

SwiftGen 깃허브

SwiftGen 라이브러리는 프로젝트의 리소스(ex, 이미지, 폰트, 컬러, 다국어 문구 등)를 Swift 코드로 자동 생성해주는 도구입니다. 이 라이브러리를 사용하면, 리소스를 편하게 사용할 수 있고 리소스를 변경했을 때(또는, 없는 리소스를 참조하려고 할 때) 에러를 빠르게 찾을 수 있습니다. 

 

라이브러리를 사용하지 않고 Xcode에서 이미지, 색상 등을 사용하려면 리소스 이름을 String으로 하여 사용해야 하는데, 오타 등의 에러는 발견하기 어렵기 때문에 쉽게 원인을 파악할 수 없습니다. 그러나 SwiftGen으로 생성된 코드로 리소스를 사용하면 프로젝트 내에 존재하는 리소스와 해당 리소스에 대한 이름을 지정해주므로 위와 같은 상황을 막을 수 있습니다. 

 

🔒 Type Safety가 부여됩니다. 

타입을 추론하는 것이 아니라, 각 변수의 타입에 맞는 타입만 저장이 가능하도록 하므로 Type Safety가 부여됩니다.

즉, 리소스를 사용할 때 image에는 image를 / color에는 color를 / font에는 font를 사용합니다.

 

    private let writingBackgroundView = UIView().then {
        $0.backgroundColor = Asset.Colors.white.color
        $0.layer.cornerRadius = 15
    }
    
    private let logoImageView = UIImageView().then {
        $0.image = Asset.Assets.icnLogoMain.image
    }

 

💬 선언적입니다.

'선언적'이다는 것은 코드가 선언형 프로그래밍을 따르고 있다는 것으로 명령형 프로그래밍과는 대비되는 개념입니다. 

 

프로그램이 어떤 방법으로 해야 하는지를 나타내는 것이 아니라 무엇과 같은지 설명하는 경우을 '선언형'이라고 합니다. 예를 들어, 웹 페이지는 선언형인데 웹 페에지는 제목/글꼴/본문/그림과 같이 무엇이 나타나야 하는지를 묘사하는 것이지 어떤 방법으로 화면에 페이지를 나타내야 하는지를 묘사하지 않기 때문입니다. 

 

📌 선언적이다 = 어떻게 보다는 무엇을에 집중하는 것

 

🤔 왜 선언적이어야 하는가? 

이미지를 그리는 방식을 생각해보겠습니다. 

 

- 명령형으로 이미지를 그리는 방식

'sokyte.png'라는 이미지 파일에 대해서 UIKit인지 AppKit인지에 따라서 UIImage, NSImage를 사용하는 코드를 모두 작성해야 합니다.

- 선연형으로 이미지를 그리는 방식 

그러나, SwiftGen을 사용하면 Asset.sokyte.image라고만 작성하면 됩니다. 

>> 이렇게 어떻게를 숨기고 실제 리소스를 사용하는 곳에서는 무엇을에만 집중하게 하는 것이 앞서 말한 타입 안정성과 코드의 간결함과 같은 이로운 결과를 제공합니다. 

 

iOS 개발에서 선언적인 기술은 SwiftUI를 예로 들 수 있습니다. 

 

✅ SwiftGen의 장점

✔️ 문자열을 사용하여 생길 수 있는 오타 위험을 방지할 수 있습니다. 

✔️ 자동 완성이 가능합니다. (-> 리소스 파일이 프로젝트 내에 있는 경우 + 빌드 한 이후)

✔️ 존재하지 않는 에셋 이름을 사용할 위험을 피할 수 있습니다. 

✔️ 위의 과정들이 컴파일 과정에서 보장되므로 앱이 런타임에서 터지는 것을 방지할 수 있습니다.

 

라이브러리 설치 

라이브러리 추가 

라이브러리 추가 (설치법은 여러가지가 있지만, 저는 Podfile을 통해서 해보겠습니다.)

pod 'SwiftGen', '~> 6.0'

 

그리고 나서 터미널을 켠 후 프로젝트 경로로 가서 

./Pods/SwiftGen/bin/swiftgen config init

위의 명령어를 입력합니다. 

 

이렇게 입력을 하고 나면, 아래와 같은 swfitgen.yml 파일이 만들어집니다. 

이렇게 파일이 자동으로 열리게 되는데, 닫아주고 프로젝트 파일을 열고 추가를 하면 됩니다.

위의 창에서 Add Files to "프로젝트 명" 을 선택해서 

파인더에서 해당 파일을 찾아 위와 같이 옵션을 설정한 뒤에 추가하면 됩니다.

❌ 이 때 copy items if needed 를 누르지 않도록 주의해야 합니다.  

 

위와 같이 파일을 추가하면 프로젝트 내에 보이게 됩니다. ⬇️

 

🤔 yml 파일이 무엇인가?

이렇게 추가한 이 파일은 .yml 확장자인 파일입니다. 구문에 YAML을 사용하는 파일을 말하는데, 연속적인 데이터를 읽기 쉽게 도와주는 파일이라고 생각하면 됩니다. (like JSON)

 

.yml 파일 수정 

다음으로 해당 파일을 열어서 입력/출력 디렉토리 경로를 넣으면 됩니다.

아래의 코드를 추가하면 됩니다.

 input_dir: Instagram/Resource
 output_dir: Instagram/Global/Constant

코드를 살펴보면, 크게 두가지 경로를 입력하게 되는데

1. input_dir : SwiftGen에게 추가될 파일 경로에 대해 탐색할 폴더를 알려주는 것

2. output_dir : 위에서 탐색한 다음, 결과물을 담을 곳으로 - 생성된 Swift 파일의 출력 디렉토리를 정의하는 변수 - 이 곳을 통해서 쉽게 SwiftGen의 파일을 추적 가능 

 

Run Script 추가 

다음으로 Run Script를 추가하면 됩니다. 

화면에서 보이는 것과 같이 클릭을 하고 나서, 아래의 코드를 Shell에 추가하면 됩니다.

if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]]; then
  "${PODS_ROOT}/SwiftGen/bin/swiftgen"
else
  echo "warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it."
fi

코드를 추가하면 아래와 같습니다.

 

여기까지 작성했다면, 순서를 drag & drop으로 옮기면 됩니다.

 

그리고 나서 빌드를 합니다. 에러가 없이 빌드가 되었다면 프로젝트 내에 SwfitGen 라이브러리가 잘 설치된 것입니다. (일단 설치는 되었고 이후에 적용을 하면 됩니다.)

 

만약 여기가지 하고 나서 에러가 났다면, 아마도 .yml에서 input_dir와 output_dir의 위치, .yml 파일의 위치 등이 꼬이거나 잘 위치해있지 않아서 생길 확률이 높습니다. 파일의 위치를 코드에서 잘 적어주었는지 확인해봅시다.

 

SwiftGen 적용하기 

이렇게까지 했다면 이제 본격적으로 프로젝트 내에서 SwfitGen을 적용해보겠습니다.

 

제가 이 프로젝트에서 관리할 리소스는 이미지와 컬러 에셋입니다. 프로젝트 내에서 아래와 같이 에셋 파일이 있고 각 파일에 이미지/컬러가 import 되어 있습니다. 이렇게 프로젝트 파일에 들어 있는 에셋에 대해서 SwiftGen을 통해 자동으로 상수화하여 사용할 예정입니다.

 

✅ swiftgen.yml 파일을 열어서 아래의 코드를 추가합니다.

 xcassets:
  inputs:
    - Asset/Assets.xcassets
    - Asset/Colors.xcassets
  outputs:
    - templateName: swift5
      params:
        forceProvidesNamespaces: true
      output: Assets+Generated.swift

위의 코드가 어떤 역할을 하는 코드인가?!

- xcassets 

SwiftGen이 해당 파일을 변환할 것을 말해주는 코드 

- inputs

SwiftGen에 대한 변환을 제한해야 하는 파일 

- outputs

SwiftGen이 변환 후에 어떻게 결과물을 낼 것인지 의미 

- templateName: swift5

SwiftGen에서 제공하는 기본 템플릿

- forceProvidersNamespaces: true

개발자가 입력한 에셋의 이름 표기가 그대로 유지됨을 의미 

- output: XCAssets+Generated.swift

SwiftGen이 변환 이후, 생성할 output 파일의 이름으로 위에서 출력 디렉토리를 적어주었는데, 해당 위치에 위의 파일 이름으로 상수화되어 추가

 

이렇게 작성하고 나서 빌드를 해봅시다. 에러 없이 빌드가 되었다면 이제 다음 단계로 넘어가보겠습니다.

(분명 위에서 output 파일을 만들어주었는데, 프로젝트 내에 안보인다고 해서 당황하지 말고 이제 그 부분을 추가하면 됩니다.)

 

 

✅ swiftgen.yml 파일을 열어서 아래의 코드를 추가합니다.

위의 이미지에서 보이는 것과 같이 직접 파일을 선택해서 추가하면 됩니다. 이 때에도 마찬가지로 ❌copy item is needed ❌를 선택하면 안됩니다.

 

✅ 추가가 잘 되었다면, 해당 파일을 열어서 Asset을 확인해보겠습니다.

위와 같이 파일 내부에 리소스에 넣어준 에셋들이 상수화 되어 있는 것을 확인할 수 있습니다.

타입 프로퍼티를 통해서 선언되었고 internal 제한자로 설정 되어 있어서 해당 열거형 이외에도 사용할 수 있습니다.

 

이것을 이제 어떻게 사용하는가?!

에셋을 사용할 곳에 가서 다음과 같이 사용할 수 있습니다. 자동완성이 되므로 에셋 파일로 이동해서 하나씩 확인하지 않고 코드를 작성할 때 바로 에셋을 적용할 수 있습니다.

 

label.textColor = Asset.Colors.mainBlue.color
imageView.image = Asset.Assets.icnLogo.image

컬러, 이미지에 대해서 모두 적용 가능합니다.

 

폰트의 경우도 폰트 파일을 추가해서 info.plist에 설정을 한 다음 (하나씩 입력하는 과정) swiftgen.yml 파일로 이동하여 

fonts:
  inputs:
    - Font
  outputs:
    templateName: swift5
    output: Fonts.swift

위와 같이 코드를 적용 후 빌드하면 새로운 Fonts 파일이 추가됩니다. 폰트 역시 위와 같은 방식으로 프로젝트에서 사용하면 됩니다.

 


 

초반에 작업할 것이 조금 있지만, 프로젝트가 진행될 수록 에셋의 양이 많아지고 하나씩 관리하는 것이 어려워지므로 SwiftGen을 사용하면 보다 빠르고 안전하게 리소스르 관리할 수 있습니다. 

 

'iOS' 카테고리의 다른 글

Apple Developer Pending  (0) 2022.04.19
Autolayout Animation  (0) 2022.04.17
iOS-Concurrency  (0) 2022.04.09
UIStackView  (0) 2022.04.04
ClipsToBounds vs MasksToBounds  (0) 2022.03.29