1. Framework: framework란?

1. Framework: framework란?

이번 포스트에서는 iOS 앱을 개발할 때 외부라이브러리로 많이 이용하는 형태인 framework에 대해서 알아보겠습니다.

Framework란?

framework는 이미지, nib파일, 다국어 문구, 문서, 공유 라이브러리리, 헤더 파일 등을 포함하는 디렉토리입니다.
framework의 목적은 code와 resource를 재사용하는 것입니다. static library(.a파일)는 코드만을 공유하지만 framework는 이미지 파일 및 다국어 파일 등 리소스 파일과 헤더파일을 framework 하나로 공유할 수 있습니다.
framework는 또한 bundle이며 NSBundle로 접근할 수 있습니다. 다른 bundle과 다르게 finder에서 보통의 디렉토리 처럼 바로 접근할 수 있습니다.

  • 주요 특징

    • framework는 관련된 항목을 하나로 묶어줍니다.
    • framework는 static library보다 다양한 리소스 타입을 포함할 수 있습니다. 예를 들어 관련된 헤더 파일과 문서를 포함할 수 있습니다.
    • 여러 버전의 framework를 하나의 bundle에 포함시킬 수 있습니다. 이 점은 오래된 프로그램에서 안정성을 가질 수 있도록 만듭니다. (macOS)

    Note: framework는 실행코드 없이 리소스 파일만 포함할 수도 있습니다. 그러나 이 방식은 일반적인 사용이 아닙니다. 이런 경우는 프로젝트 생성시 bundle로 생성할 수 있습니다.


  • 구조
    MyFramework.framework/
        Modules/
            module.modulemap
        Headers/
            MyFramework.h
        MyFramework
        Resources
    
    MyFramework.framework의 디렉토리 구조는 위와 같습니다.
    MyFramework.framework 디렉토리 아래에 Modules와 Headers 서브디렉토리가 있습니다.
    Headers 디렉토리에는 framework에서 사용할 수 있는 code에 대한 header파일들이 위치합니다.
    modules는 module설정 관련 파일들이 위치합니다.
    MyFramework실행파일과 resource파일들은 MyFramework.framework 디렉토리 아래에 위치합니다.

  • 종류
    framework에는 static framework와 dynamic framework가 있습니다.

    • Static framework
      static linker를 통해 라이브러리를 link할 때 framework가 앱의 실행파일에 복사됩니다. static linker는 object code라는 컴파일된 소스코드를 수집하고 하나의 실행파일에 합칩니다. runtime시에 메모리에 전체가 로드됩니다.
      큰 실행파일이 로드되어야하기 때문에 실행시간이 오래 걸릴 수 있고 메모리 공간을 많이 사용할 수 있습니다.
      enter image description here

    • Dynamic framework
      static framework와 다르게 dynamic framework는 실행파일의 일부가 아닙니다. dynamic framework는 앱이 실행되고 나서 로드될 수 있습니다.
      xcode에서 dynamic framework를 사용할 때 link binary에 추가하는 것 뿐만 아니라 embed framework에도 추가해야합니다. dynamic framework는 실행파일에 추가되지 않기 때문에 App내에 추가한 후 사용할 때 로드됩니다.
      enter image description here



Framework 생성 규칙

  • 이름규칙
    클래스, 함수, 전역변수는 유일한 이름이어야 합니다. 2단계 namespace는 dynamic link가 runtime에 올바른 symbol을 찾을 수 있도록 돕습니다. 그러나 static link는 중복된 심볼이 정의된 경우 링크 오류를 발생시킬 수 있습니다.
    예를 들어 같은 이름을 정의한 두개의 다른 framework가 있고 새로운 프로젝트에 둘다 포함했다고 가정하겠습니다.
    중복된 심볼을 참조하면 static linker에서는 오류가 발생합니다. dynamic linker에서 2단계 namespace를 생성하고 어떤 심볼을 접근할 지 힌트를 제공합니다.
    명확하고 관련된 이름을 지어야합니다. 접두어는 구분하는데 도움을 줍니다.

  • umbrella framework를 만들지 마라
    xcode에서 umbrella framework를 생성할 수 있지만 대부분의 개발자에게를 불필요하며 권장하지 않습니다. Apple에서는 라이브러리와 OS사이에 독립적인 구성을 위해서 일부 사용합니다. 대부분의 경우에 하나의 표준 framework로 구성이 가능합니다.



Framework 생성하기

framework를 직접 만들어 보겠습니다.

  1. xcode를 실행하여 새로운 proejct를 생성합니다.
    iOS탭에서 framework를 선택하고 다음을 선택합니다.
    enter image description here

  2. framework의 프로젝트 이름을 설정하고 언어는 swift로 선택합니다.
    enter image description here

  3. 프로젝트가 생성이 완료되면 아래와 같이 표시됩니다.
    enter image description here

  4. Test.swift 파일을 생성하고 아래와 같이 작성합니다.

    import UIKit
    
    public class Test: NSObject {
        public func test() {
            print("MyFramework: test!!")
        }  
    }
    

    접근제어를 public이상으로 설정해야 외부에서 framework API를 사용할 수 있습니다.

  5. framework를 dynamic library나 static library로 설정할 때는 build settings의 Mach-O Type을 통해 변경할 수 있습니다. 기본은 dynamic library로 설정됩니다.
    enter image description here

  6. MyFramework를 사용할 MySample 프로젝트를 single app으로 생성합니다.
    enter image description here

  7. MyFramework.framework를 MySample 프로젝트에 추가하고 프로젝트 설정의 libraries, Embedded Content에서 Embed로 설정합니다.
    여기서 주의할 사항이 framework를 dynamic library로 설정한 경우는 'embed’로 설정하고 static library로 생성한 경우는 'do not embed’로 설정해야합니다.
    enter image description here

  8. ViewController.swift파일에 아래와 같이 코드를 작성하고 실행하면 framework가 잘 동작하는 것을 확인할 수 있습니다.

    import UIKit
    import MyFramework
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let test = Test()
            test.test()
        }
    }
    
    // 실행결과
    // MyFramework: test!!
    
  9. 또한, MyFramework 생성 시 Objective-C에서 사용할 수있도록 MyFramework-Swift.h 파일이 자동으로 생성됩니다.
    Objective-C파일에서 아래와 같이 import해서 사용할 수 있습니다.

    #import <MyFramework/MyFramework-Swift.h>
    // 또는
    @import MyFramework;
    

※ Ojective-C로 생성할 때

  1. framework 프로젝트 생성할 때 언어를 Objective-C로 설정합니다.
    enter image description here

  2. TestClass.h와 TestClass.m파일을 생성한 후 코드를 아래와 같이 작성합니다.

    // TestClass.h 파일
    
    #import <Foundation/Foundation.h>
    
    @interface TestClass : NSObject
    
    - (void)test;
    
    @end
    
    
    
    // TestClass.m 파일
    #import "TestClass.h"
    
    @implementation TestClass
    
    - (void)test {
        NSLog(@"MyFramework2: test!!");
    }
    
    @end
    
  3. 외부에서 TestClass를 사용할 수 있도록 Build Phases탭-headers에서 public항목에 TestClass.h파일을 추가합니다.
    enter image description here

  4. MyFramework2.h파일을 아래와 같이 작성합니다.

    #import <Foundation/Foundation.h>
    
    //! Project version number for MyFramework2.
    FOUNDATION_EXPORT double MyFramework2VersionNumber;
    
    //! Project version string for MyFramework2.
    FOUNDATION_EXPORT const unsigned char MyFramework2VersionString[];
    
    // In this header, you should import all the public headers of your framework using statements like #import <MyFramework2/PublicHeader.h>
    
    #import <MyFramework2/TestClass.h>
    
    

    public 헤더에 추가한 헤더파일은 MyFramework2.h파일에 추가해줘야합니다. framework를 import할 때 MyFramework2.h 헤더파일 하나로 framework에서 사용할 수 있는 모든 헤더파일을 간편히 참조할 수 있습니다. 또한, swift에서 framework를 사용하기 위해서 추가해야합니다.




지금까지 framework에 대해서 알아보고 직접 생성해 보았습니다.
다음 포스트에서는 한 프로젝트에서 여러 framework를 사용할 때 발생할 수 있는 이름 충돌에 대해서 알아보겠습니다.




참고

댓글

이 블로그의 인기 게시물

dismiss에 대해서 알아봅시다

closure에서는 왜 self를 사용해야 할까?