보통 프로젝트를 새로 만들면 하나의 프로젝트에 모든 코드와 리소스를 때려박아서 개발을 진행한다.
(내가 그럼 ㅇㅇ)
하지만 프로젝트 내에 서브 프로젝트를 만들어 소스 코드를 추가하고,
오직 상위 프로젝트에서만 서브 프로젝트의 코드를 알도록 Build Phase -> Dependencies를 이용할 수 있다.
프로젝트, 서브 프로젝트
프로젝트내에 서브 프로젝트를 만들어서 관리할 수 있다.
이는 해당 프로젝트의 코드가 많아지면 서브 프로젝트를 만들어 관리하는 것이다.
예제 : http://minsone.github.io/ios/mac/ios-framework-part-2-project-subproject-dependencies
- SampleApp 프로젝트를 생성한다.
- SampleApp 프로젝트 내에 Service 서브 프로젝트를 생성한다.
- 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는 적은 숫자로 유지된다.
- Service 서브 프로젝트 내에AppLogService 서브 프로젝트 생성
- AppLogService -> Build Settings -> Linking -> Mach-O Type을 Static Library로 변경
- 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를 확인하자.
- Service.project의 Product -> Service.framework 파일 선택후, 오른쪽에서 Pull Path를 얻는다.
- 터미널에서 수행
- Service library의 Symbol 목록을 확인하다보면 AppLogService의 코드가 있는 것을 확인할 수 있다.
이는 Static Linker가 AppLogService Static Library를 Service Dynamic Library에 복사함을 확인할 수 있다.
그렇다면, Service 프로젝트는 서브 프로젝트만 관리하는 프로젝트인 경우
만약 Service 프로젝트는 서브 프로젝트들만 관리하는 프로젝트이고, 사용할 때는 AppLogService 프로젝트의 Service를 호출하여 사용한다면 어떻게 될까?
즉, Service 프로젝트에서 AppLogService 프로젝트를 호출하는 코드가 하나도 없고, SampleApp 프로젝트에서만 호출한다면?
- Service 프로젝트의 Service.swift 코드 제거
- SampleAPp의 AppDelegate에서 다음과 같이 코드 작성
- SampleApp의 Product->SampleApp.app 파일 선택 후, 오른쪽에서 Pull Path 확인
- 터미널로 명령 실행
SampleApp의 바이너리의 Symbol 목록에서 AppLogService Static Library 코드가 복사된 것을 확인할 수 있다.따라서 Linker가 Static Library를 사용하는 곳에 코드를 복사함을 알 수 있다.
이야기를 확장해보면, AppLogService의 Service 클래스의 Bundle 위치는 Service 프레임워크가 아니라, SampleApp이 된다.
만약에 해당 클래스가 Storyboard나 nib를 사용하는 ViewController의 경우, 코드가 있는 Bundle 위치와 Storyboard나 nib가 있는 Bundle의 위치가 달라진다.
개발자가 예상하지 못한 곳에 코드가 있으면 안되기 때문에, Static Library를 강제로 우리가 원하는 곳에 복사되도록 해야 한다. - 즉, 상위 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을 사용하여 원하는 기능을 구현해보자.
- Service 프로젝트 내에 빈 module.modulemap 을 생성
- module.modulemap 파일 내에 코드 추가
- Service 프로젝트의 Build Settings -> Packaging -> Module Map File에 코드 추가
- Service 프로젝트의 Service.swift 파일에 코드 추가
- module.modulemap 파일에 코드 수정
- SampleApp의 AppDelegate에 코드 작성
'iOS' 카테고리의 다른 글
[iOS] Bundle, Package, Framework 란? (0) | 2021.06.03 |
---|---|
[iOS] Storyboard, Xib, Color, Image를 리소스 프레임워크 관리 (3) (0) | 2021.06.01 |
[iOS] Dynamic/Static Framework (1) (0) | 2021.06.01 |
[iOS] Framework vs Library / 모듈화 (0) | 2021.06.01 |
[iOS] UIView / 레이아웃 업데이트 관련 메소드 (0) | 2021.05.24 |