Home > Software design >  I added Objective-C files to Swift package via modulemap file, but implementation wasn't connec
I added Objective-C files to Swift package via modulemap file, but implementation wasn't connec

Time:06-24

I have a Swift package, and try to add Objective-c files.

My package now:

Root
- Package.swift
  Sources
    ObjC
      DataDeflate
      - DataDeflate.h
      - module.modulemap
      - NSData Deflate.h
      - NSData Deflate.m
    Swift
      DataDeflator
      - DataDeflatow.swift
  Tests
    DataDeflatorTests
    - DataDeflatorTests.swift

Package.swift content:

import PackageDescription

let package = Package(
    name: "DataDeflator",
    products: [
        .library(name: "DataDeflator", targets: ["DataDeflator"]),
    ],
    targets: [
        .target(
            name: "DataDeflator",
            dependencies: ["DataDeflate"],
            path: "Sources/Swift/DataDeflator"),
        .systemLibrary(name: "DataDeflate", path: "Sources/ObjC/DataDeflate"),
        .testTarget(
            name: "DataDeflatorTests",
            dependencies: ["DataDeflator"]),
    ]
)

module.modulemap content:

module DataDeflate [system] {
  header "DataDeflate.h"
  link "DataDeflate"
  export *
}

DataDeflate.h content:

#ifndef DataDeflate_h
#define DataDeflate_h

#import "NSData Deflate.h"

#endif /* DataDeflate_h */

Now, using these settings (module.modulemap and targets in Package.swift), Swift code has access to Objective-C NSData category. But only for declaration (NSData Deflate.h), and not to implementation (NSData Deflate.m)!

When I add Objective-C method calling, it builds successfully, without any warnings. But unrecognized selector sent to instance error appears when unit tests runs.

What did I forget? How can I connect both declaration and implementation from Objective-C to Swift?

CodePudding user response:

You don't need to use systemLibrary target with a modulemap file for your own ObjC source files because usually it's used as wrapper to available C system libraries such as sqlite3, curl etc. and the modulemap file can be created for your target automatically by XCode.

So you can use simple target:

...
targets: [
    ...
    .target(name: "DataDeflate", path: "Sources/ObjC/DataDeflate"),
]
...

Next you should organise your files inside DataDeflate folder next way:

- Package.swift
  Sources
    ObjC
      DataDeflate
          include
            - DataDeflate.h
            - NSData Deflate.h
        - NSData Deflate.m
...

Where include subfolder must contain <YourTargetName>.h (DataDeflate.h) file and all other public headers to include.

  • Related