안녕하세요.
최근 프로젝트에 모듈화를 적용해 보면서 Library와 Framework에 대해서 나아가 Static과 Dynamic은 어떤 차이인지 정리해 보고, 상황에 따라 어떤 것을 선택해야 하는지 정리해 보기 위해 이 글을 작성합니다.

Library와 Framework
Library와 Framework는 공통된 목적의 소스 코드를 묶어 독립적으로 배포할 수 있다는 공톰점이 있다. 때문에 둘은 모듈화의 도구로 사용된다. 하지만, 둘이 완전이 동일한 동작을 한다면 Apple은 둘을 분리하지 않았을 것이다.
둘의 차이는 천천히 알아보도록 하고, Library 먼저 살펴보겠다.
Library란
Library는 소스 코드와 데이터들의 집합이다. 독립적으로 배포 가능하기 때문에 재사용성이 높은 소스 코드를 Library를 통해 관리할 수 있다. 또한, Library는 이미지와 같은 리소스 자원을 포함할 수 없다.
Library는 두가지 타입으로 나뉜다.
- Static Library
- Dynamic Library
Static Library

Static Library는 정적 라이브러리로 파일 확장자는 .a이며, 앱 컴파일 시점에 위 이미지와 같이 앱 소스 코드에 함께 포함되어 빌드된다.
이를 직접 확인해 볼 수 있는데 라이브러리를 직접 생성 및 App 프로젝트에 추가 후 빌드해보면,

위와 같이 MyApp이라는 Bundle이 생성되고, 내부에는 MyApp의 실행 파일과 plist와 같은 앱 실행에 필요한 리소스 파일들이 존재한다.
nm --debug-syms MyApp | grep "\.o"
위 명령어를 통해 MyApp의 실행 파일 내부를 확인해보면,

내부에 MyLibrary의 오브젝트 파일이 포함되어 있는 것을 확인할 수 있다.
정적 라이브러리는 이 처럼 앱 실행 파일에 함께 포함되어 배포되기 때문에 정적 라이브러리를 많이 사용하거나 큰 라이브러리를 정적으로 사용하면 앱 사이즈가 그만큼 커지고, 이는 곧 앱의 메모리 사용량이 증가하고 실행 시간이 느리다는 뜻이다.
또한, 정적 라이브러리의 수정 발생하면, 다음과 같이 App도 다시 빌드되어야 한다. 하지만, 소스 코드가 실행 파일에 포함되어 있기 때문에 접근 속도가 빠르다.
Dynamic Library

Dynamic Library는 동적 라이브러리로 확장자는 .dylib이다. 동적 라이브러리는 정적 라이브러리와 다르게 앱 소스 코드에 라이브러리 코드가 포함되는 것이 아닌 참조 값을 가지고, 라이브러리의 소스 코드가 호출될 때 해당 코드를 Stack 영역에 로드 후 사용한다.
때문에. 정적 라이브러리에 비해 메모리 사용량이 줄어들고, App 실행 시간이 빠르다. 또한, 동적 라이브러리의 경우 수정이 발생했을 때 수정된 라이브러리만 빌드되며, App에서 수정된 소스 코드를 불러올 수 있다.
모듈화를 진행하는 대표적인 이유로 빌드 시간 감소가 있는데 이는 Dynamic Library를 사용했을 때만 해당한다.
동일하게 App의 실행 파일 내부를 확인해 보면,

정적 라이브러리 때와 다르게 위와 같이 실행 파일에 라이브러리 코드가 포함되어 있지 않은 것을 확인할 수 있다.
대신, 아래 명령어를 통해 동적 라이브러리 목록과 각 라이브러리의 경로, 버전 정보 등을 확인할 수 있다.
otool -L MyApp

하지만, iOS OS에선 동적 라이브러리를 사용하지 못한다. 실제로 라이브러리를 생성할 때도 정적 라이브러리만 생성 가능하다.
iOS에서 동적 라이브러리가 동작하지 않는 이유를 몇가지 실험을 통해 추측해 봤을 때(⚠️ 개인적인 생각입니다. 사실과 다를 수 있음)
iOS에서 동적 라이브러리는 아래와 같이 번들에 포함되지 않는다.

때문에, 참조를 통해 주소 값을 알지만, 접근할 수 없기 때문이라고 생각된다.
실제로, 동적 라이브러리를 지원하는 MacOS의 경우

위와 같이 번들 내부에 동적 라이브러리 파일이 포함되어 있다.
해당 글에서도 동적 라이브러리는 System iOS와 macOS를 제외하고는 지원하지 않는다고 소개하고 있다.
추가로, iOS의 경우 Mach-O Type을 동적 라이브러리로 변경해도 확장자가 정적 라이브러리의 확장자인 .a로 고정되어 있는데 라이브러리의 확장자는 Mach-O Type에 따라 달라지는 것이 아닌 라이브러리를 생성할 시점의 Type을 따라가는 것 같다.
동적 라이브러리를 지원하는 MacOS에서도 정적 라이브러리로 생성 후 Mach-O Type을 동적 라이브러리로 변경했을 때도 빌드 결과 .a로 확장자가 변경되지 않았다.
정리
- Library
- 소스 코드와 데이터의 집합
- 이미지와 같은 리소스 자원은 포함할 수 없음
- Static Library
- 컴파일 시 App 실행 파일에 소스 코드가 포함됨
- App의 실행 파일의 사이즈가 커지고, 실행 시간이 느림
- 라이브러리 수정 시 App 또한 다시 빌드 되어야하기 때문에 빌드 효율성이 떨어짐
- 소스 코드 접근 속도는 빠름
- Dynamic Library
- 참조를 통해 런타임 시점에 소스 코드를 Stack에 할당하여 사용
- 메모리와 실행 시간 측면에서 정적 라이브러리에 보다 이점이 있음
- 수정이 발생했을 때 App까지 빌드할 필요가 없음
- 참조를 통해 실제 코드에 접근해야 함으로 접근 속도는 다소 떨어짐
- iOS에서는 지원하지 않음
추가로, 정적 라이브러리의 경우

위와 같이 모듈끼리 의존한다고 가정했을 때 모듈 C의 소스 코드가 모듈 A와 모듈 B에게 복사되기 때문에 최종적으로 App에서 모듈 C의 소스 코드가 중복되는 문제가 발생할 수 있다. 이를 해결하기 위해선 모듈 C를 동적 라이브러리로 변경해줘야 한다.
Framework란
Framework는 계층 구조를 갖는 디렉토리 형태를 띄고 있다. .a 확장자 파일 딸랑 하나있는 라이브러리와 다르게 Framework는 아래와 같이 헤더 파일, plist 등 다양한 정보를 담고있다.

또한, Framework의 경우 Library와 다르게 이미지와 같은 리소스 파일을 포함할 수 있고, 특이하게 실행 파일이 존재한다.
Framework에 관련된 글을 찾아보면 "Framework의 경우 코드 호출 및 흐름 제어권을 갖는다." 라는 말을 많이 하는데 이러한 특징 때문에 가능한 것 같다.
Framework 또한 Library와 동일하게 Static, Dynamic 두 가지 타입을 갖는다.
Static Framework
Framework를 생성했을 때 기본값은 Dynamic이기 때문에 Build Settings에서 Mach-O Type을 Static Library로 변경해주어야 한다.
특징은 정적 라이브러리와 동일하게 컴파일 시 앱 실행 파일에 소스코드가 포함된다. Framework의 차이점은 App Target에서 Embed를 설정할 수 있다.

Embed를 Embed & Sign으로 설정하게 되면 App 번들에 Framework가 포함되게 된다.
반대로 Do Not Embed로 설정하면 번들에 Framework가 포함되지 않는다.
정적 프레임워크의 경우 App 실행 파일에 이미 프레임워크의 소스 코드가 포함되어 있기 때문에 번들에 포함시킬 필요가 없다. 때문에 Embed를 Do Not Embed 설정하는 것을 권장한다. 만약, 프레임워크에 리소스가 포함되어 있는 경우 Embed & Sign로 설정하여 번들에 포함시켜야한다. App 실행 파일에는 소스 코드만 포함되기 때문이다.
라이브러리 때와 동일하게 번들 내부를 확인해 보면,

plist와 실행 파일이 있고, 실행 파일 내부를 보면,

정적 라이브러리 때와 동일하게 프레임워크의 소스 파일이 포함되어 있는 것을 확인할 수 있다.
Dynamic Framework
Dynamic Framework 역시 동작 원리는 Dynamic Library와 동일하다.
또한, 앞서 Dynamic Library에서 언급했던 변경에 따른 빌드 결과를 보면, 수정된 Framework만 빌드되고 App은 따로 빌드되지 않는다.(이는 상황에 따라 결과가 달라질 수 있다.)
하지만, Dynamic Framework는 iOS에서도 사용이 가능하다. 가능한 이유는 앞서 언급한 Embed를 통해 App 번들에 포함 시킬 수 있기 때문이다. Embed를 Embed & Sign으로 설정 및 프레임워크의 Mach-O Type을 Dynamic Library로 변경 후 빌드해보면,

App 실행 파일 내부에 프레임워크의 소스 코드가 사리지고,

번들 내부에 Freamworks라는 디렉토리가 생성된다. 또한, 라이브러리 때와 동일하게 otool -L MyApp를 통해 확인해 보면,

동적 프레임워크의 경로를 확인할 수 있다. 프레임워크의 소스 코드가 호출됐을 때 해당 경로를 통해 소스 코드를 Stack에 할당 후 사용할 수 있게된다.
정리
- Framework
- 디렉토리 형태의 계층 구조를 가짐
- 소스 코드 외에도 이미지와 같은 리소스 파일을 포함할 수 있음
- Static Framework
- 동작 원리는 Static Library와 동일
- Embed를 Do Not Embed 설정하는 것 권장
- 하지만, 리소스가 포함되어 있는 경우 Embed & Sign으로 설정해야함 (대신 소스 코드 중복이 발생)
- Dynamic Framework
- 동작 원리는 Dynamic Library와 동일
- Embed를 Embed & Sign 설정해야함 안 그럼 크래쉬 발생
- iOS에서도 지원함 (유일한 Dynamic 타입의 모듈을 사용할 수 있는 방법)
Framework의 경우에는 iOS에서도 Dynamic 타입을 지원하기 때문에 Dynamic Framework를 통해 Dynamic Library의 성능적 이점을 가져갈 수 있다.
마무리
Library와 Framework, Static과 Dynamic에 대해 알아보았다. 아직 풀이지 않은 점도 많고, 추측성 결론도 있기 때문에 계속 자료를 찾아봐야 할 것 같다.
초반에 언급한 대로 이번 글의 목표는 Framework와 Library 나아가 Static과 Dynamic을 사용하는 나만의 기준을 만드는 것이다. 그래서 정리해본 나만의 기준은 다음과 같다.
- 사이즈가 큰 모듈 → Dynamic Framework
- 변경이 자주 발생하는 모듈 → Dynamic Framework
- 크기가 작고, 변경이 자주 발생되지 않는 모듈 → Static Library
- 다수의 상위 모듈이 의존해야하는 모듈 → Dynamic Framework
참고
'iOS&Swift' 카테고리의 다른 글
| Swift Data VS Core Data (0) | 2026.02.13 |
|---|---|
| [Swift] @Environment에 대해 알아보기(Property Wrapper 3편) (0) | 2024.01.20 |
| [Swift] @ObservedObject와 @StateObject의 차이에 대해 알아보기(Property Wrapper 2편) (0) | 2024.01.20 |
| [Swift] @State, @Binding, @Published 대해 알아보기(Property Wrapper 1편) (0) | 2024.01.19 |
| [Swift] Alamofire의 RequestInterceptor을 사용해 토큰 갱신하기 (0) | 2024.01.18 |