• Stars
    star
    345
  • Rank 122,750 (Top 3 %)
  • Language
    Objective-C
  • License
    Eclipse Public Li...
  • Created about 10 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Develop iOS apps with ClojureScript

Goby

Develop iOS apps with ClojureScript.

platform :ios, '8.0'
pod "Goby", "~> 1.1.0"

Clojars Project

Overview

This repository contains some lightweight ClojureScript and Objective-C glue code that facilitates creating iOS apps where the view controllers are written in ClojureScript instead of Objective‑C or Swift. Otherwise the resulting iOS apps are native, with the JavaScript running in an embedded JavaScriptCore instance.

The overall design includes decorators for various UIKit elements, each implementing the JSExport protocol so that interop can be established between the ClojureScript code and the UI elements. Goby treats the UI as a bunch mutable state that can be manipulated or listened to, with atoms in the ClojureScript code simply holding references to the decorators.

When needing to provide Objective-C protocol implementations such as UITableViewDataSource, Goby provides an equivalent ClojureScript protocol, along with some glue code and a reify macro, making it possible to implement the Objective-C protocol directly in ClojureScript. The case where some of the Objective-C methods are optional is handled.

A few other things are thrown in to get things off the ground, like some infrastructural glue code to manage the loading of the JavaScript, along with simple facilities for method dispatch from the iOS to ClojureScript namespaces. ClojureScript keywords for various iOS SDK enumeration constants are defined to make life easier.

As such, Goby is fairly minimal, simply providing some structure to help establish communication between the Objective-C and ClojureScript sides of the fence. It doesn't attempt to provide a sophisticated framework supporting a functional programming style. But, it at least gets you to the point where you are coding in ClojureScript. :)

This approach was used to build an app currently in the App Store and this repo is derived from the reusable bits from that project.

Usage

Check out the companion working example project Shrimp illustrating actual use of this code.

Roughly speaking, the overall steps are:

  1. Set up sibling iOS and ClojureScript projects and make the Goby iOS and ClojureScript code available to each. (The Shrimp project provides a working example of this where the Goby dependencies are managed via CocoaPods and Clojars.)
  2. The ClojureScript for your app compiles down to JavaScript which is included as a reference in the iOS project bundle.
  3. In your [AppDelegate application:didFinishLaunchingWithOptions:] set up an instance of GBYManager, which loads the ClojureScript-compiled JavaScript, and adds a few callback handlers as needed for logging and timers.
  4. Create a view using Storyboards in Xcode’s interface builder as usual, and wire the UI elements to your view controller header as you would normally do. Create a "glue" UIViewController class for this view by extending GBYViewController. Make your view controller call into the ClojureScript when the view is loaded, passing in decorated references to UIKit elements.
  5. On the ClojureScript side, create a namespace that mirrors the name of your view controller, and make use of the defui macro to set up atoms for each of your UI elements and to ^:export a method that the Objective-C side can use to initialize the UI element atoms. (Of course, all of this could be coded by hand, but this is an example where the Goby code can reduce repeated boilerplate for each view controller.)
  6. Add code in your ClojureScript namespace to set up UI events handlers, perform application logic as needed, update UI elements, etc. In other words, implement your app logic in ClojureScript. :)
  7. Add more views and view controllers, and segues between them, as you normally would. In the end, the application primarily consists of a set of ClojureScript namespaces covering the various view controllers, along with ancillary application-level ClojureScript needed to flesh out your application.

REPL

You can use a REPL while developing, inspecting and manipulating UI and other app state, revising function implementations, etc. I have found that I need to restart my iOS app when making Storyboard changes, or other significant changes. The Shrimp project discusses establishing a REPL.

Performance

Launch time performance is good. On an A5 (which is used by the iPhone 4s, iPad 2, and iPod touch), the Google Closure optimized JavaScript for my production app is loaded in around 380 milliseconds.

At runtime, one area where you can often see performance issues in iOS is when implementing scrolling table views. In my production app, I have table views being driven by ClojureScript, initializing cells using data on the ClojureScript side, etc., and I have seen no stuttering when scrolling.

Otherwise, I've arguably been using the ClojureScript to "orchestrate" the otherwise native iOS UI and native iOS animations, and have had no performance issues in going this route.

For tasks such as using HTTP for image fetching or REST API calls, I simply make use of the fine native AFNetworking library, driving it from ClojureScript.

Project Status

I have used Goby to create one production app in the App Store. I'm maintaining Goby, fleshing out aspects of the Goby code as needed. As such the code is incomplete in some areas, has some rough corners in others, and questionable—but workable—design in others.

For future apps, I'm instead focusing on using ClojureScript with Om and React Native. This leads to a much saner architectural style, adhering to FP principles, embracing immutability, etc. Goby was created in a world that didn't have React Native. I am no longer pushing forward with the imperative approach used by Goby. To learn more about React Native with ClojureScript, see cljsrn.org.

License

Copyright © 2014–2017 Mike Fikes and Contributors

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

More Repositories

1

ambly

ClojureScript REPL into embedded JavaScriptCore
Objective-C
540
star
2

cljs-bean

Efficient JavaScript object interop via idiomatic ClojureScript
Clojure
305
star
3

esprit

ClojureScript on the ESP32 using Espruino
Clojure
138
star
4

tubular

Clojure Socket REPL client
Clojure
85
star
5

bocko

Simple Clojure imperative graphics
Clojure
75
star
6

reagent-react-native

Demo project for Reagent with React Native
Objective-C
59
star
7

advent-of-code

Advent of Code in Clojure, ClojureScript, HP BASIC, Objective-C
Objective-C
57
star
8

shrimp

Example project using Goby
Objective-C
51
star
9

coal-mine

Clojure(Script) compiler characterization tests corpus
Clojure
38
star
10

esprit-board

37
star
11

react-native-externs

Google Closure extern files for React Native
JavaScript
34
star
12

tach

Test self-hosted ClojureScript libs with lein
Clojure
26
star
13

chivorcam

Macros directly in ClojureScript
Clojure
23
star
14

ilk

Type tools for ClojureScript
Clojure
18
star
15

indole

A rate limiting algorithm for Clojure(Script)
Clojure
16
star
16

auto-completion

ClojureScript React Native Om Next Auto-Completion
Objective-C
15
star
17

mt-cljs

Multithreaded ClojureScript
Clojure
14
star
18

titrate

Test with bootstrap ClojureScript
Clojure
12
star
19

elbow

Use Replumb in Node
Clojure
12
star
20

cljs-perf

ClojureScript compiler perf measurements
11
star
21

self-host-etl-pipeline

Self-host ETL Pipeline
Clojure
11
star
22

precise

Tagged literals for exact
Clojure
9
star
23

bocko-ios

Render Bocko onto iOS with ClojureScript
Objective-C
8
star
24

fifth-postulate

Test ClojureScript parallel compilation speedup
Clojure
8
star
25

om-react-ios-components

Using 3rd party React iOS components with Om
Objective-C
7
star
26

cljs-cl

Experiment with ClojureScript command-line app (compiled to Java byte code)
Clojure
7
star
27

derevo

Builds ClojureScript :foreign-libs graph from JS files
Clojure
6
star
28

ambient

Example of using ambient functions from self-hosted ClojureScript
Clojure
6
star
29

patch-tender

Check and test with ClojureScript patches
Clojure
6
star
30

morse-key-ble-bridge

Connect Morse key as a Bluetooth keyboard
C
5
star
31

bentho

Support utilities for React Native
Objective-C
4
star
32

sucnm

Structure and Use of ClojureScript Namespaces with Macros
Clojure
3
star
33

closurecomp

Checks that ClosureScript works fine with latest Closure Compiler and Library
3
star
34

hp-85-utils

Utilities for working with the HP-85
BASIC
2
star
35

clik-clak-joe

React Native tic-tac-toe in ClojureScript
Clojure
2
star
36

impedance-converter

Impedance Converter
Swift
2
star
37

nash-this

Illustrates a collision problem in Nashorn related to this.state=state in ctors
Clojure
1
star
38

arb

Arbitrary waveform file generation utilities
Clojure
1
star
39

battery-models

1
star
40

word-clouds

Sorted word frequencies for word clouds
Clojure
1
star
41

battery-discharge

Keithley Battery Discharge Sample App port for the Keithley 2400 SourceMeter
Python
1
star
42

pwl-utilities

Utilities for working with LTspice PWL files
Python
1
star
43

rn-commonjs

Test React Native commonjs processing
Clojure
1
star
44

test-commonjs

Testing ClojureScript CommonJS support
Clojure
1
star
45

signalsonic

SignalSonic Morse Code Safari Extension
JavaScript
1
star
46

workarounds-1.10.439

Monkey patches to workaround CLJS-2955
Clojure
1
star
47

aardvark-qwiic-adapter

Adapter from Total Phase Aardvark 10-pin connector to QWIIC pins, along with GPIO breakout
1
star