Using Chilkat from Swift on iOS
Chilkat's iOS API is an Objective-C library. Swift calls it through a bridging header — the same mechanism used for any Objective-C library. This page covers the setup, how to call Chilkat from Swift, and the problems most often encountered.
Jump to: How Swift uses Objective-C Bridging header Link & flags Name mapping Calling Chilkat Unlocking Common problems
How Swift uses an Objective-C library
Swift can call Objective-C code directly, but it needs to be told which Objective-C
headers to expose. That is the job of the Objective-C bridging header — a
single .h file in which you #import the Objective-C headers
you want to use. Once the bridging header is configured:
- The imported classes (Chilkat's
Ckoclasses) become available throughout your Swift code — noimportstatement is needed in your.swiftfiles. - Objective-C classes, methods, and properties are exposed to Swift — though
Swift adapts the names to its own conventions (see
How Objective-C names map to Swift), and Foundation types
bridge automatically (for example
NSString↔String).
This is exactly how you would consume any Objective-C library from Swift; Chilkat is no different.
Step 1 — Add an Objective-C bridging header
-
Create the bridging header
Add a header file to your project named
YourProject-Bridging-Header.hand import the ChilkatCkoclasses your app uses:#import <Foundation/NSObject.h> #import "chilkat-ios/include/CkoGlobal.h" #import "chilkat-ios/include/CkoJsonObject.h" #import "chilkat-ios/include/CkoHttp.h" // Import each Cko*.h header your app uses. // The path depends on where you extracted the Chilkat headers, // and must be on your Header Search Paths.
If you added Chilkat as an XCFramework, the headers travel with it, so you can usually import as
#import "CkoJsonObject.h"without a separate path. -
Point Xcode at the bridging header
Set Build Settings → Swift Compiler - General → Objective-C Bridging Header to the path of that file (relative to your project). Xcode also offers to create and wire up a bridging header automatically the first time you add an Objective-C file to a Swift project.
Step 2 — Link the library and add linker flags
Add the Chilkat static library (or XCFramework) to your target under Build Phases → Link Binary With Libraries (click +, then Add Other…). The library to link depends on your platform:
libchilkatIos.a— iOSlibChilkatCocoa.a— macOSlibChilkatWatchOS.a— watchOSlibChilkatTvOS.a— tvOS
Then, in Build Settings → Other Linker Flags, add:
-lresolv -lpthread -lc++
How Objective-C names map to Swift
When Swift imports an Objective-C class, it does not use the Objective-C names verbatim. The Swift compiler adapts them to Swift's naming conventions, which affects three things:
- Method names — the first letter is lower-cased.
Objective-C
UpdateStringbecomes SwiftupdateString. - Property names — likewise lower-cased.
Objective-C
EmitCompactbecomes SwiftemitCompact, andVersionbecomesversion. - The first argument of a method — in Objective-C the first parameter has no call-site label, but Swift gives it one (the parameter's name). Later arguments keep their existing labels.
For example, the same JSON call in each language:
[json UpdateString: @"test.abc[0].xyz" value: @"Chicago Cubs"];
json.updateString(jsonPath: "test.abc[0].xyz", value: "Chicago Cubs")
Note the three differences: UpdateString → updateString,
the first argument gained the label jsonPath:, and the trailing
value: label is unchanged.
updateString(jsonPath:value:)), while the Objective-C reference
documentation shows the Objective-C names (e.g. UpdateString:value:).
When writing Swift, follow the Swift reference; when writing Objective-C, follow the
Objective-C reference.
Calling Chilkat from Swift
A few more things to keep in mind when calling Chilkat from Swift:
- Construction:
[[CkoJsonObject alloc] init]becomesCkoJsonObject()!— the initializer returns an implicitly-unwrapped optional, hence the!. - Strings bridge automatically: a Chilkat method returning
NSString *returns a SwiftString. - Numeric properties typed as
NSNumbermust be set and read asNSNumberin Swift (see the troubleshooting note below).
// No 'import Chilkat' is needed — the bridging header exposes the classes. let json = CkoJsonObject()! json.emitCompact = false json.updateString(jsonPath: "author.name", value: "Chilkat") print(json.emit()!)
Unlocking Chilkat
Chilkat runs as a fully functional 30-day trial out of the box. Unlock it once at app startup. Pass any non-empty string for the trial, or your license code after purchase:
let glob = CkoGlobal()! let success = glob.unlockBundle(bundleUnlockCode: "Anything for 30-day trial") if !success { print(glob.lastErrorText!) }
Common problems
Cause: the bridging header isn't set, points to the wrong file, or doesn't import that class's header.
Fix: confirm Objective-C Bridging Header
in Build Settings points to your *-Bridging-Header.h, and that the file
#imports the needed Cko*.h header. The setting is
per target — set it for each target (app, tests, extensions) that uses
Chilkat.
Cause: the #import path in the bridging header doesn't resolve,
or the headers' folder isn't on the search path.
Fix: use the correct path to the Chilkat include
directory and add it to Header Search Paths. (With an
XCFramework the headers are bundled, so import by file name only.) Note the iOS
headers are under chilkat-ios/include — not the macOS
chilkat-macosx-objc path.
std::, res_query, pthread_*)Cause: the required system libraries aren't linked.
Fix: add -lresolv -lpthread -lc++ to
Other Linker Flags. Chilkat is built with the LLVM C++
standard library, so it is -lc++ (not -lstdc++).
Cause: the linked static library is for the wrong platform — e.g. a device library while building for the simulator (or a library that mixes device and simulator slices).
Fix: link the device library for device builds and the simulator library for simulator builds, or use an XCFramework so Xcode selects the right binary automatically. See Building an iOS Universal Static Library or XCFramework.
Cause: some Chilkat numeric properties are typed as
NSNumber, which does not implicitly convert to/from a Swift
Int.
Fix: wrap and unwrap explicitly, for example
obj.someIndex = NSNumber(value: 0) to set, and
let n = obj.size?.intValue to read.
Cause: Chilkat returns autoreleased objects; a background thread you create needs its own autorelease pool.
Fix: wrap the work in autoreleasepool { ... }. See
Auto-release Pools and Background Threads.