Framework를 만들어보자 !

Jee.e (황지희)·2023년 9월 15일
1

모듈화의 여정

목록 보기
2/4

시작하기 전에, 먼저 간단히 몇가지 개념만 짚고 넘어가겠습니다!

  • Library
    • 함수나 클래스와 같은 단순 활용이 가능한 도구들의 집합
    • 어렵게 말하면, 패키징된 Object file들의 모음
      • Static Libray와 Dynamic Library가 존재
  • Framework
    • Library, Header File, Resource(storyboards, image, localized, 문서 등)를 하나의 Bundle로 묶어놓은 것
    • iOS에서 Bundle에 관련 파일을 하나의 패키지 (이미지, 컴파일된 코드)로 편리하게 함께 제공
    • 즉 Framework가 Library를 포함할 수 있고, Library보다 큰 개념임
  • Bundle
    • 내부에 있는 파일 디렉토리
    • iOS에서 Bundle은 App에 관련된 파일을 하나의 패키지로 제공하는 역할
  • Executable file
    • 앱 실행을 위한 바이너리

그럼 바로 Framework를 만들어보겠습니다 👯‍♂️


Framework 생성

  1. 먼저 Xcode에서 Framework를 선택해 프로젝트를 생성해줍니다!

  2. 이제 Framwork의 기능을 구현해주면 되는데, 저는 아래와 같이 Padding Label을 만드는 함수를 선언했습니다!

  3. 그리고, 프로젝트 파일(Ex. App)을 생성합니다.

  4. 생성한 프로젝트에서 Add Files to [ Project Name ]… 를 해주고,
    앞서 만든 Framework를 추가해줍니다.

  5. 그럼 아래와 같이 정상적으로 Framework가 프로젝트에 들어온 걸 확인할 수 있습니다.

  6. General ➡️ Frameworks, Libraries, and Embedded Content 에도 추가해줍니다!

  7. 가져온 Framework를 사용하기 위해 import CustomFramework 를 해주고,
    앞서 만든 Framework의 코드를 적용하면 .. !

  8. 아래와 같이 정상적으로 표출이 되는 것을 확인할 수 있습니다 ~!



Static Framework로 변경하기

앞서 기술한대로, Framework를 만들면 기본적으로 Mach-O Type 이 DynamicLibrary로 되어있습니다.

이걸 StaticLibrary로 변경해주었습니다!

Products ➡️ Show in Finder ➡️ 매인 앱 실행파일 ➡️ 패키지 내용보기 까지 하면
만든 Framework의 소스 코드로부터 생성된 Object File이 들어있는 Unix 실행 파일을 확인할 수 있습니다!
(마지막 이미지에 보이는 App)!

App Project 빌드하면,
Framework 코드를 포함해 위와 같은 최종적인 App(App Project) Executable(실행파일)이 생성됩니다! (모든 코드를 포함 X, 필요한 부분만 선택적으로 Load)

Static Framework 사용시 App size가 커진다고 말하는 이유가 이것입니다.

🤔 App Executable에 Framework 코드가 포함된 걸 어떻게 확인할 수 있나?

위 이미지와 같이 Executable 파일이 있는 경로에 들어가, 터미널에 명령어 하나만 입력하면 됩니다!

nm -debug-syms [프로젝트 이름] | grep "\.o”

그럼 이렇게 .. !

앞서 만든 Framework의 PaddingLabel.o 과 UIHelper.o 를 포함해,
App Project의 파일이 포함되어 있는 것을 확인할 수 있습니다!

그리고, 같은 폴더에 Framework라는 폴더가 있습니다!

내부에는 위와 같이 만들어 놓은 Framework가 위치해있는데요!

file Frameworks/Jiee_sFramework.framework/Jiee_sFramework 와 같이 해당 파일을 file 명령어로 확인해보면!

이렇게 정적 라이브러리 라는 것을 확인할 수 있습니다!


💡current ar archive가 정적 라이브러리인 이유 ?

무조건 정적 라이브러리에 국한되지 않지만,
ar 은 정적 라이브러리(컴파일된 Object file들이 하나의 아카이브로 묶여있는 상태)를 만들어 주는 명령어(Object file들을 묶어 주는) 입니다.
참고 문서


근데, 위 폴더는 중복된 리소스입니다.

이미 Object file이 들어있는 App(Unix 실행 파일)이 있기 때문이죠!

없애는 방법은 상당히 간단합니다.

  • 앞서 설정했던 General ➡️ Frameworks, Libraries, and Embedded Content ➡️ Framework - Embed & sign 을 ➡️ Do Not Embed로 바꾸어주면 됩니다!
  • 그리고, 빌드 후 폴더를 확인해보면 아래와 같이 깔-끔하게 삭제되어있는 것을 확인할 수 있습니다!

🤔 그렇다면, Dynamic Library App Executable은 어떻게 구성되어있을까?

역시나 nm -debug-syms [프로젝트 이름] | grep "\.o” 명령어를 사용해보았습니다!

오,, 위 Static Library 와 다르게 JiheeFramework의 Object File이 없네요..
(당연함 ㅇㅇ. RunTime시점에 동적으로 로드하기 때문)

Dynamic Library는 주소 정보를 Heap에 저장하고있다가, Runtime 시점에 코드를 Stack에 할당하는 구조입니다.
이때 App이 Library 실행파일을 참조합니다!

otool -L [프로젝트 이름] 명령어를 사용하면, App이 참조하고 있는 Shared library 를 확인할 수 있습니다!

해당 파일의 위치는 위 내용과 이어지는데요!

이렇게 Framework의 실행파일을 확인할 수 있습니다!

Framework를 앱과 연결하면 처음엔 Dynamic Library고,
General ➡️ Frameworks, Libraries, and Embedded Content ➡️ Framework - Embed & sign 로 설정해주었죠!

Dynamic Library 사용시 반드시 위 설정을 진행해야만, 폴더와 파일(실행 파일)이 생성되게 됩니다!

만약 Do Not Embed 로 설정한다면?

App package 내부에 Frameworks가 포함되지 않기 때문에,
dyld: Library not loaded 라는 동적 링커 에러가 발생합니다.

dyld ?

  • dyld 는 Dynamic Library를 Load하기 위한 것으로, 메인 실행파일에서 시작합니다.
  • Mach-O를 파싱해 종속 dylib - 필요한 Dynamic Library를 찾습니다.
  • Dynamic Library 사용시,
    App을 프로그램 파일 하나만 로드하지 않고, 모든 dylib들을 로드하고 연결합니다.
    때문에 App 실행속도가 느립니다.

모듈화 .. StaticLibrary로 .. ? 아님 DynamicLibrary .. ?

Static Lib와 달리, Dynamic Lib은 재 컴파일 없이 RunTime에 업데이트되거나 새로 대체될 수 있습니다. (Runtime Flexibility)

라이브러리간의 버전이 다른 경우에도 동일한 이름의 객체/클래스를 충돌 없이 사용할 수 있습니다.

다만, RunTime시점에 Dynamic Library의 파일이 준비되어 있어야하기 때문에, 그만큼 라이브러리를 관리하기 위한 더 많은 자원이 필요합니다.

또 라이브러리 코드가 동적으로 로드되기 때문에, 정적 라이브러리를 사용할때보다 시간이 더 소요됩니다.

++ 버전 관리에 더 많은 신경을 써야하고, 지나친 모듈화(DLL 파일이 많은) 상황에서는 모듈별로 디버깅하기가 어려워집니다.

정해진 정답은 없고, 모듈의 특성에 따라 Static or Dynamic 을 결정하면 됩니다.

주로 아래와 같이 구현한다고 합니다!

  • Static Library
    • 전체 소스를 제공하지 않고 SDK 형태로 배포하는 경우
  • Dynamic Library
    • 리소스를 가지고 있거나 전체 소스를 제공하는 경우

++ 생성한 Library가 3rd Party 의존성을 갖고있다면, Dynamic Library로 구현해야합니다.

이런 경우 Static Library로 구현하게 되면, Linking이 되지않아 에러가 발생하기 때문입니다! (전체 코드가 로드되는게 아니기때문)


틀린 내용을 알려주시면 감사하겠습니다 🙇‍♀️🙇‍♀️

참고 문서

profile
교훈없는 경험은 없다고 생각하는 2년차 iOS 개발자입니다.

0개의 댓글