Skip to article
Integrations / Swift

Swift

The same engine for iOS and macOS, with the same results as TypeScript.

On this page

The Swift SDK brings the engine to iOS 16+ and macOS 13+, with no third-party dependencies. It is a port of the TypeScript engine and gives the same results: conformance tests compare the two on every query of the eval set.

Install

Package.swift
dependencies: [
  .package(url: "https://github.com/emojisense/emojisense-swift.git", from: "0.1.0"),
],
targets: [
  .target(
    name: "App",
    dependencies: [.product(name: "Emojisense", package: "emojisense-swift")]
  ),
]

Usage

Swift
import Emojisense

// 1. Load the core packs. English is always first.
let packURL = URL(string: "https://api.emojisense.com/v1/pack/0.1.0")!
let loader = PackLoader(baseURL: packURL)
let manifest = try await loader.loadManifest()
let core = try await loader.loadPacks(locales: ["en", "tr"], manifest: manifest)
var engine = try AliasEngine(core: core)

// 2. Search on every keystroke. Synchronous and fast.
let alias = engine.search("jurassic pa", options: AliasSearchOptions(locale: "en"))
var results = alias.results.map(\.searchResult)

// 3. When the device is idle, add the extension parts and rebuild the index.
let extensions = try await loader.loadPacks(
  locales: ["en", "tr"], part: .ext, manifest: manifest)
engine = try AliasEngine(core: core, extensions: extensions)

// 4. Semantic layers: static shards first, then the API.
let semantic = ProviderChain([
  ShardProvider(baseURL: URL(string: "https://api.emojisense.com/p/0.1.0")!),
  SemanticClient(
    configuration: .init(
      endpoint: URL(string: "https://api.emojisense.com")!, key: "pk_live_…",
      packVersion: engine.packVersion)),
])
if Fusion.shouldUseSemantic(alias),
  let response = try await semantic.search("jurassic pa", options: .init(locale: "en"))
{
  results = Fusion.fuse(alias: alias, semantic: response.results)
}
  • Debounce the semantic call, for example by 200 ms, and cancel the task when the query changes.
  • AliasEngine is thread-safe.
  • SemanticClient returns nil while it pauses after an overLimit answer, and throws EmojisenseError.httpStatus for HTTP errors. ShardProvider returns nil on network errors, so the next provider gets the query.
  • Inject an HTTPTransport to add headers, logging or a stub for tests.

Parts

TypeWhat it does
AliasEngineOffline dictionary search over the packs. Runs on every keystroke.
NormalizerQuery and label normalization, as in the pack format.
Pack, PackLoader, ManifestDecode the core and extension packs and verify their SHA-256.
ShardProviderPrecomputed semantic results from static shards (layer 2).
SemanticClientThe API in semantic mode, with an LRU cache. Over the limit it still gets the edge’s cached answers.
FusionThe same pinned reciprocal rank fusion as the TypeScript SDK.
EmojiSet, HexcodeThe emojiSet option of the pickers: .native or a hosted set. imageURL(for:endpoint:) gives the image URL. No UI.

Performance

In a release build on Apple silicon, with the English and Turkish core and extension packs, a keystroke takes 0.04 ms at the median and 0.28 ms at the 95th percentile. Building the index from decoded packs takes 0.27 s. You can also bundle the pack files in your app and decode them with try Pack(jsonData: data).