~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atirc-ios-client

0
1
main
48 lines · 2.5 KB Raw History

Go + Swift in AT-IRC

PoC, 2026-10-30.

Result

Possible. gomobile bind (golang.org/x/mobile) emits a static AtircGo.xcframework linked into the app. No dynamic library, no embedding; App Store-safe.

Setup

  • Install both tools: go install golang.org/x/mobile/cmd/{gomobile,gobind}@latest. bind shells out to gobind; installing only gomobile fails with "gobind was not found".
  • GoLib/go.mod: module atirc/golib; requires golang.org/x/mobile/bind.
  • GoLib/golib.go: exported Version, Echo, SHA256Hex, ParseCommand, Counter.
  • Build: gomobile bind -target=ios,iossimulator -o GoLib/AtircGo.xcframework atirc/golib.

Bridging

  • string <-> NSString; []byte <-> NSData (byte slices are mutable, passed by reference).
  • Exported struct -> ObjC class (GolibCounter), methods/properties bound.
  • (T, error) -> NSError**; Swift sees an explicit NSErrorPointer, not throws. Max two results; second must be error.
  • Calls are synchronous; goroutines work.

Type limits (gobind docs)

  • Supported: signed ints, floats, string, bool, []byte, functions, interfaces, structs with supported exported fields/methods.
  • Unsupported: other slices, maps, channels, generics; docs list signed ints only.
  • A panic crossing the boundary exits the process.
  • Proxy reference cycles leak.
  • Go can also call ObjC directly via reverse bindings (import "ObjC/Foundation/NSDate").

Xcode

  • Per-SDK FRAMEWORK_SEARCH_PATHS must point at the slice, not the xcframework parent: .../AtircGo.xcframework/ios-arm64 (device) and .../ios-arm64_x86_64-simulator (sim).
  • OTHER_LDFLAGS = $(inherited) -framework AtircGo. Static framework: nothing to embed.
  • UpdateTargetBuildSetting rejects [sdk=...] keys; set them in project.xcproj JSON.

Validated (iPhone, iOS 27.2)

  • Tests pass: strings, []byte <-> Data, struct + methods, (T, error) -> NSError, goroutines, Go -> Swift callbacks.
  • Interface collides with generated class, so Swift sees GolibCallbackProtocol.
  • Callbacks arrive on a Go thread; hop to MainActor before touching UI.

Size (Release, arm64)

  • Wrapper unreferenced: 0 delta (dead-stripped).
  • Wrapper referenced (force-loaded): 1.1 MB -> 3.1 MB binary (+2.0 MB); Go __text +768 KB.

Rebuild

  • GoLib/build.sh; GoLib/AtircGo.xcframework is gitignored.

Caveats

  • iOS sandbox: no os/exec/fork; networking OK.
  • Device slice ~5.2 MB unstripped; app stripping applies.
  • Regenerate after Go changes (candidate Run Script phase; script sandboxing is ON).