• Basics of interoperability
    • Swift는 이미 Objective-C 기반으로 되어있는 수많은 앱이 있는 상태에서 등장했기 때문에 기존 코드 베이스와 함께 쓸 수 있는 기능이 필수적이였다.

      • 이를 통해서 Swift를 점진적으로 적용할 수 있게 만들었다.
    • 이제 C++ 코드베이스를 가진 곳에서도 Swift를 점진적으로 적용할 수 있다.

    • Swift에서 C++ 라이브러리를 쓸 수 있다.

      • 더 이상 Objective-C 브릿징 레이어는 필요 없다.
      • Bridging header도 필요없다.
      • interoperability mode를 C++/Objective C++로 맞추면 된다.
    • C++ 프레임워크도 그냥 자연스럽게 import하면 된다.

      import CxxImageKit
      
    • 호출도 자연스럽게

      • 다만 그냥 가져오면 unsafepointer형태로 import가 되어버린다.

        func loadImage(_ image: UIImage) {
            // Load an image into the shared C++ class.
            CxxImageEngine.shared.pointee.loadImage(image)
        }
        
    • Objective-C++쪽에서는 generated된 헤더를 import하면 된다.

      #import "SampleApp-Swift.h"
      
    • 사용도 쉽게

      - (IBAction)openPhotoLibrary:(UIButton *)sender {
          // Construct SwiftUI view
          SampleApp::ImagePicker::init().present(self);
      }
      
    • 이 상호 운용은 양방향이고, 컴파일러에 의해 자동적으로 이뤄진다.

    • 모든 호출은 직접 이뤄지기 때문에 오버헤드가 없다.

    • C++ → Swift

      • Collection: std::vector, std::map, 사용자 정의 콜렉션
      • Templates: 함수 템플릿 및 클래스 템플릿 특수화
      • Smart Pointer: std::shared_ptr, 사용자 정의 포인터
      • Swift는 이를 고수준에서 받아들이고, 최적화를 잘 해줄 수 있다.
    • Swift → C++

      • Members: methods, properties, initializers
      • Generics: struct, enum 모두
      • Standard library: swift::Array, swift::String, swift::Optional
      • Library evolution: resilient struct and classes
    • Xcode에서 지원

      • 코드 완성
      • Jump to definition
      • 리네이밍
      • 디버거 지원
  • Natural Swift APIs
    • Swift 가 C++ API를 가져오는 규칙: 가져와서 안전하게 만들 수 있어야 한다.

      • C++ 타입은 기본적으로 struct로 가져온다.

      • C++ 연산자는 비슷한 Swift연산자로 매핑된다.

      • 컨테이너는 Collection으로 매핑된다.

        스크린샷 2023-06-13 오후 11.54.45.png

    • 다만 컴파일러에 추가 어노테이션을 좀 더 주면 좀 더 자연스럽게 쓸 수 있게 가져와준다.

      • 계산 프로퍼티의 accessor

        int  getValue() const SWIFT_COMPUTED_PROPERTY;
        void setValue(int newValue) SWIFT_COMPUTED_PROPERTY;
        
        var value: Int { get set }
        
      • reference semantic

        struct SWIFT_SHARED_REFERENCE(retain, release) CxxReferenceType;
        
        class CxxReferenceType
        
      • 안전하지 않은 API를 가져오기

        SWIFT_RETURNS_INDEPENDENT_VALUE 
        std::string_view netwrokName() const;
        
        func networkName() -> std.string_view
        
    • std::vector in Swift

      • C++ 타입은 기본적으로 값 타입으로 import 된다. 그래서 std::vector도 값타입이다.

      • 차이점은 Swift는 해당 타입의 특수한 멤버인 복사 생성자를 써서 생명주기를 관리한다는 것이다.

        • 이 복사 생성자는 종종 깊은 복사를 구현한다.
        • 그래서 vector를 복사하면 변경 여부와 관계없이 깊은 복사가 일어난다.
      • vector에 대해서 for-loop를 돌릴 수 있다.

        // Get every image out of the shared C++ class.
        for image in CxxImageEngine.shared.pointee.getImages() {
            let uiImage = CxxImageEngine.shared.pointee.uiImageFrom(image)
            UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
        }
        
      • 이는 vector가 begin과 end 메소드를 가지고 있기 때문으로, 이 두가지를 가지고 있으면 어떤 타입이던 자동적으로 Swift collection으로 import된다.

        • Array로 바꾸거나, map, filter를 자유롭게 쓸 수 있다.
      • C++ iterator API보다는 Swift Collection API를 쓰는 게 안전하다.

        • Iterator는 생명주기 이슈나 잘못된 메모리 접근 등이 쉽게 발생한다.

        • Collection API를 쓰면 C++콜렉션을 쓰더라도 안전을 보장해준다.

        • 그래서 이것도 막아준다.

          스크린샷 2023-06-14 오전 12.47.25.png

    • 참조타입

      • C++에는 값타입과 참조 타입의 구분이 명확하지 않기 때문에, Swift는 모든 타입을 값타입으로 일단 가져온다.

      • 참조타입으로 가져오기 위해서는 C++ 코드 쪽에서 annotation을 넣어줘야 한다.

        #import <swift/bridging>
        
        // 커스텀 retain, release 메소드
        void IKRetain(CxxImageEngine *_Notnull engine);
        void IKRelease(CxxImageEngine *_Notnull engine);
        
        struct SWIFT_SHARED_REFERENCE(IKRetain, IKRelease) CxxImageEngine {
            // ...
        };
        
      • 이러면 unsafePointer indirection을 없앨 수 있다.

    • 계산 프로퍼티 만들기

      /// \\returns all images that have been loaded into the engine. Includes any modifications that were
      /// applied to the images.
      SWIFT_COMPUTED_PROPERTY
      inline std::vector<Image *_Nonnull> getImages() const;
      
    • 완성본

      // Get every image out of the shared C++ class.
      for image in CxxImageEngine.shared.images {
          let uiImage = CxxImageEngine.shared.pointee.uiImageFrom(image)
          UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
      }
      
    • 이 외에도 많은 annotation을 지원한다.(헤더)

  • 모든 Apple 플랫폼과 Windows, Linux도 지원
  • C++은 크고 복잡한 언어기 때문에 이를 발전시키고 싶고, 피드백이 많이 필요하다.
  • 이후에 상호 운용 방법이 변경되어도 문제가 없도록 버전으로 관리할 것이다.