Bundle

  • 실행 가능한 코드와 리소스를 갖고 있는 디렉토리
  • 가지고 있는 내용 - info.plist, assets, string 등
  • Framework Bundle은 Dynamic Library에서 사용하는 코드와 라소스를 포함
  • 모든 Application Bundle은 App에 대한 정보가 담긴 info.plist를 가짐

Package

Finder가 사용자에게 단일 파일로 보여주는 디렉토리

 

 

NSBundle

  • Bundle에 포함된 코드와 리소스에 대한 표현
  • NSBundle은 Objective-C 를 통해 만들어진 Foundation Class이며, Bundle 디렉토리 내에 포함된 리소스에 쉽게 접근할 수 있도록 제공하는 객체

Main Bundle

Bundle은 여러가지가 있다.

그 중 mainBundle은 App이 실행되는 코드가 있는 Bundle 디렉토리에 접근할 수 있게 도와주는 Bundle

 

 

Copy Bundle Resource

  • mainBundle에 들어가 있는 리소스 파일들은 빌드할 때, 추가됨
    • Xcode의 Build Phase에 존재 - "Copy Bundle Resources"
    • 해당 항목에서 App에 추가할 리소스를 결정
    • 해당 항목이 없는 리소스는 Project Navigator에 추가되어 있어도 실제로 Bundle을 통해 접근 불가

 

Framework

공유자원(Dynamic Library, nib, 이미지 등)을 단일 패키지로 담고 있는 디렉토리

Framework는 Library와 달리 리소스를 포함할 수 있고, Framework를 모듈 배포를 통해 Library보다 많은 활용 가능

Framework는 파일 시스템의 Bundle로 패키징되어, Core Foundation Bundle Service를 이용 가능

NSBundle class로 접근 가능

 

 

 

각각의 기능으로 분리되어 있는 프로젝트들은 공통의 리소스를 가질 수 있다.

Color, Image, Lottie의 JSON 등을 포함한다.

각각의 프로젝트들은 공통의 리소스를 사용하여 개발해야 하기 때문에, 리소스 Framework를 만들어 관리할 수 있다.

중복되는 이미지도 없고, 리소스 Framework를 import만 하면 된다.

 

Image, Color를 리소스 Framework으로 관리

먼저 리소스 Framework를 만든다. 그리고 이미지를 Images.assets에 추가한다.

 

해당 이미지들은 외부에서 코드로 불러와 사용하는 경우가 있기 때문에, 이미지를 외부에서 접근할 수 있는 코드를 만든다.

Resource Framework는 R 이라는 타입으로 접근하여 사용할 것이다.

 

먼저 R 타입을 만들자.

Framework로 만들었기 때문에, 이미지를 불러올 때 Resource Framework의 Bundle 위치를 알기 위해 내부에서 사용할 Bundle을 만들었다.

이제 이미지를 외부에서 접근할 수 있는 코드를 R.Image.[이미지이름] 형태를 따르도록 만든다.

 

 

이제 외부에서는 다음과 같이 이미지를 불러올 수 있다.

 

Color도 Image와 마찬가지로 만들 수 있다.

 

 

Storyboard, Xib를 리소스 Framework에서 관리

iOS 개발시, 항상 논쟁이 되는 주제가 있다. 바로 View를 Storyboard vs Xib로 작성하는 것이다.

 

Storyboard 파일을 갖기 위해서는 Dynamic Framework를 만들어야하는데, 각 기능마다 Framework로 만들게 되면 Framework 개수가 빠른 속도로 늘어날 뿐만 아니라, 기능을 더 작게 나눠 한 화면을 Framework로 만들면 어마어마할 것이다.

 

따라서 Storyboard, Xib를 리소스 Framework에서 관리하면 된다.

리소스 Framework에서 관리하면 화면 단위의 Framework를 Static으로 만들어도 Bundle의 위치가 리소스 Framework이기 때문에 문제가 없다.

그리고 Storyboard, Xib에서 이미지와 Color를 지정해도 Framework 자신의 내부에서 가져오기 때문에 문제가 없다.

 

그렇다면 다른 Framework에 있는 UIViewController Class와 ViewController View를 어떻게 연결할까?

 

위 사진처럼 Module을 선택하고 해당 UIViewController Class 선택하면 된다.

 

사용은

 

 

 

 

 

 

 

 

보통 프로젝트를 새로 만들면 하나의 프로젝트에 모든 코드와 리소스를 때려박아서 개발을 진행한다.

(내가 그럼 ㅇㅇ)

 

하지만 프로젝트 내에 서브 프로젝트를 만들어 소스 코드를 추가하고,

오직 상위 프로젝트에서만 서브 프로젝트의 코드를 알도록 Build Phase -> Dependencies를 이용할 수 있다.

 

프로젝트, 서브 프로젝트

프로젝트내에 서브 프로젝트를 만들어서 관리할 수 있다.

이는 해당 프로젝트의 코드가 많아지면 서브 프로젝트를 만들어 관리하는 것이다.

 

예제 : http://minsone.github.io/ios/mac/ios-framework-part-2-project-subproject-dependencies

 

[iOS][Xcode] Framework Part 2 : 프로젝트, 서브 프로젝트, Dependencies, 그리고 Static, Dynamic Framework

서론 프로젝트를 만들면 해당 프로젝트 내에 서브 프로젝트를 만드는 것에 이야기를 들어본적이 없었습니다. 프로젝트 하나에 모든 코드와 리소스가 다 들어가도록 개발을 했기 때문입니다. 하

minsone.github.io

 

  1. SampleApp 프로젝트를 생성한다.
  2. SampleApp 프로젝트 내에 Service 서브 프로젝트를 생성한다.
  3. SampleApp's General -> Frameworks, Libraries and Embedded Content에 Service.framework 추가

Framework를 만들면 기본으로 Dynamic Framework로 지정된다. 즉, 위의 방식으로 서브 프로젝트들을 많이 만들게되면 SampleApp 프로젝트에는 많은 Dynamic Framework가 임베딩된다.

 

그것이 맞는 방법일까?

그렇다면 Dynamic Framework 프로젝트를 만들고, 해당 서브 프로젝트로 Static Framework를 만들면 어떻게 될까?

-> Dynamic Library에 Static Library의 코드가 복사되기 때문에, 서브 프로젝트는 많아질 수 있어도, Dynamic Framework는 적은 숫자로 유지된다.

 

  1. Service 서브 프로젝트 내에AppLogService 서브 프로젝트 생성
  2. AppLogService -> Build Settings -> Linking -> Mach-O Type을 Static Library로 변경
  3. Service 서브 프로젝트의 Build Phases -> Dependencies 에서 AppLogService Framework 추가

Service 프로젝트는 Dynamic Framework이며, AppLogService 프로젝트는 Static Framework이다.

그러므로 Service 프로젝트가 빌드되면서 Service Dynamic Library에 AppLogService Static Library가 복사될 것이다.

 

코드를 작성해주자

 

AppLogService

 

Service

SampleApp

 

이후 빌드하면, 생성된 Service Framework의 Dynamic Library를 확인하자.

  1. Service.project의 Product -> Service.framework 파일 선택후, 오른쪽에서 Pull Path를 얻는다.
  2. 터미널에서 수행
  3. Service library의 Symbol 목록을 확인하다보면 AppLogService의 코드가 있는 것을 확인할 수 있다.
    이는 Static Linker가 AppLogService Static Library를 Service Dynamic Library에 복사함을 확인할 수 있다.


 

그렇다면, Service 프로젝트는 서브 프로젝트만 관리하는 프로젝트인 경우

만약 Service 프로젝트는 서브 프로젝트들만 관리하는 프로젝트이고, 사용할 때는 AppLogService 프로젝트의 Service를 호출하여 사용한다면 어떻게 될까?

즉, Service 프로젝트에서 AppLogService 프로젝트를 호출하는 코드가 하나도 없고, SampleApp 프로젝트에서만 호출한다면?

 

  1. Service 프로젝트의 Service.swift 코드 제거
  2. SampleAPp의 AppDelegate에서 다음과 같이 코드 작성


  3. SampleApp의 Product->SampleApp.app 파일 선택 후, 오른쪽에서 Pull Path 확인



  4. 터미널로 명령 실행
    SampleApp의 바이너리의 Symbol 목록에서 AppLogService Static Library 코드가 복사된 것을 확인할 수 있다.따라서 Linker가 Static Library를 사용하는 곳에 코드를 복사함을 알 수 있다.

    이야기를 확장해보면, AppLogService의 Service 클래스의 Bundle 위치는 Service 프레임워크가 아니라, SampleApp이 된다.
    만약에 해당 클래스가 Storyboard나 nib를 사용하는 ViewController의 경우, 코드가 있는 Bundle 위치와 Storyboard나 nib가 있는 Bundle의 위치가 달라진다.
    개발자가 예상하지 못한 곳에 코드가 있으면 안되기 때문에, Static Library를 강제로 우리가 원하는 곳에 복사되도록 해야 한다.
  5. 즉, 상위 Dynamic Framework에서 더미로 코드를 사용해줘야 한다.


AppLogService를 SampleAppdㅔ서 import시, Service.AppLogService로 사용할 수 없을까?

SampleApp에서 AppLogService를 import Service.AppLogService와 같은 방법으로 AppLogService 프레임워크를 호출하고 싶을 수 있다.

왜냐하면 AppLogService 프로젝트는 AppLog로 바꾸어서 Service 프로젝트의 AppLog를 담당하는 서비스라고 생각하고 작업할 수 있다.

SampleApp에서 import Service.AppLogService로 import하면, No such module 'Service.AppLogService' 에러 발생

하지만 UIKit의 UIViewController는 import UIKit.UIViewController로 사용 가능하다.

 

따라서 modulemap을 사용하여 원하는 기능을 구현해보자.

 

  1. Service 프로젝트 내에 빈 module.modulemap 을 생성
  2. module.modulemap 파일 내에 코드 추가


  3. Service 프로젝트의 Build Settings -> Packaging -> Module Map File에 코드 추가


  4. Service 프로젝트의 Service.swift 파일에 코드 추가


  5. module.modulemap 파일에 코드 수정


  6. SampleApp의 AppDelegate에 코드 작성


 

 

XCode에서는 Framewokr라는 것을 통해 모듈화 단위의 코드/리소스를 사용할 수 있다.

그리고 외부 소스를 가져다 사용할 때, Cocoapods, Carthage 같은 도구를 사용할 수 있다.

 

Framework에 대해 알아볼 것들

  1. 어떻게 구성되어있는가?
  2. 어떻게 동작하는가?
  3. Static/Dynamic 차이는 무엇인가?
  4. 전체적인 개발방식

Framework

Dynamic Shared Library, Nib 파일, 이미지, 다국어 문자열, 헤더 파일 등과 같이 공유 리소스를 패키지로 캡슐화하는 계층 구조 파일 디렉토리 이다.

그리고 Framework도 Bundle이며 NSBundle로 접근이 가능하다.

또한, 리소스 사본은 프로세스 수에 상관없이 항상 물리적으로 메모리에 상주하며, 리소스 공유로 풋 프린트를 줄이고 성능을 향상시킨다.

 

Dynamic Framework

XCode에서 Framework를 만들면 기본적으로 Dynamic Framework로 만들어진다.

Dynamic Framework는 동시에 여러 프레임워크 또는 프로그램에서 동일한 코드 사본을 공유하고 사용하므로, 메모리를 효율적으로 사용한다.

동적으로 연결되어 있으므로, 전체 빌드를 다시하지 않아도 새로운 프레임워크 사용이 가능하다.

 

Static Linker를 통해 Dynamic Library Reference가 Application 코드(Heap)에 들어가고, 모듈 호출시 Stack에 있는 Library에 접근하여 사용한다.

 

Static Framework

Static Framework는 Static Linker를 통해 Static Library 코드가 Application 코드 내로 들어가 Heap 메모리에 상주한다.

따라서 Static Library가 복사되므로, Static Framework를 여러 Framework에서 사용하게 되면, 코드 중복이 발생한다.

 

Library는 Framework가 아니라 Static Library가 복사된 곳에 위치하므로, Bundle의 위치는 Static Framework가 아닌 Static Library가 위치한 곳이 된다.

때문에 번들을 접근할 때는 스스로가 접근하기보다는 외부에서 Bundle의 위치를 주입받는 것이 좋다.

 

어떤 타입을 사용해야 하는가?

일반적으로 리소스를 스스로 갖고 있거나 전체 소스를 제공하는 경우 -> Dynamic Framework

그렇지 않고 SDK 형태로 배포하는 경우 -> Static Framework

 

 

 

 

 

+ Recent posts