← Back to Home
Golf Clicker app icon

Golf Clicker — iPhone + Apple Watch Golf Stroke Counter

Hojung Lim  ·  Personal iOS project, 2026  ·  Version 1.2  ·  Swift, SwiftUI, SwiftData, WatchConnectivity, WidgetKit, ActivityKit

Swift SwiftUI SwiftData watchOS WatchConnectivity WidgetKit ActivityKit Live Activities String Catalogs XCTest Offline-first Free on the App Store Source is private
Live on the App Store · In active development View on the App Store

Project Overview

Count every stroke. Nothing else. A deliberately minimal, fully offline golf stroke counter for iPhone and Apple Watch. Count strokes from your wrist while your phone stays in your pocket, or while another golf app (e.g. 18Birdies) is open on the phone. No account, network, backend, or iCloud. Every version so far is completely free.

Version 1.2 is shaped by golfers playing real rounds. They told us they play 9 holes or stop early, sometimes skip a hole, and often don't care about par. 1.2 makes the app fit those rounds and adds a Settings screen, while keeping counting fast and the iPhone ↔ Watch sync safe.

1–18
Holes per round: finish after any hole, pass holes you skip
6
Accent themes, synced to the watch, widgets and Live Activity
104
XCTest unit tests (20 in 1.0, 34 in 1.1)
0
Network calls; all data stays on the device

What's New in 1.2 and Why

App Screenshots (1.2)

iPhone

Apple Watch

Simulator screenshots: iPhone 17 and Apple Watch 46 mm.

Feature Tour

Active round

Big hole number; Thru / Score / Total pills; an optional Par 3 / 4 / 5 selector with a clear button; and a large circular stroke button with haptics that works immediately. Undo, Pass and Finish Hole sit below. The crossed-out flag in the top bar ends the round at any hole.

Hole states

StateMeaningCounts in totals
Not playedA future hole, or an empty hole when the round endedNo
In progressThe current holeNot yet
CompletedFinished with Finish Hole (at least 1 stroke)Yes; versus par only if par is set
PassSkipped on purpose, after confirmation; strokes, if any, were deleted. Can be resumed from the scorecard while the round is in progressNo
IncompleteThe round ended while this hole had strokesNo; strokes are kept and shown with a warning

Scorecard

During a round all 18 holes are listed. A finished round shows only the holes played, so a 9-hole round has no empty Back 9. Pass and Incomplete are always written out with text and an icon, never color alone. Tap any finished hole to set or change its par or strokes; totals recalculate.

Round History

Each round shows "9 holes · 1 passed", total strokes, and score versus par only when every counted hole has par; otherwise it says how many holes are missing par. Swipe to delete with a single centered confirmation.

Apple Watch

The big-button counter with Undo and Finish Hole, sized to fit 40–49 mm cases. The flag button opens a native list with Pass Hole and Finish Round, so the counting screen stays uncluttered. Counting keeps working when the iPhone is out of reach. The complication and Smart Stack card from 1.1 follow the current hole, and the Smart Stack card uses the chosen theme.

Settings and themes

Classic Green (the original look), Ocean Blue, Sunset Orange, Royal Purple, Rose Pink and Midnight. Themes change accent colors only. The watch can match the iPhone or use its own theme. The Apple Watch section reads its status from the real connection state, and "Last synced" only updates after the watch confirms it received the data.

Live Activity / Dynamic Island

Lock Screen and Dynamic Island views with hole, par (when set), strokes and "Thru n · total · +/-", in the chosen theme, updated after every change including watch taps.

Architecture

Watch tap ──► WatchEvent (id, absolute count, base revision) ──► sendMessage (durable queue if the iPhone is away) ──► iPhone: dedupe ──► RoundStore (one atomic save) ──► RoundSnapshot + preferences ──► Watch, widgets, Live Activity
ComponentResponsibility
RoundStore Single entry point for every round change. Enforces the hole-state transition table, saves each change atomically and rolls back on failure.
Versioned SwiftData schema V1 is the 1.0/1.1 model; V2 adds the round's final hole. A lightweight migration upgrades existing stores without rewriting rounds, verified by a test that opens a real 1.x store file.
PhoneSyncCoordinator / WatchSyncCoordinator WatchConnectivity. The phone publishes snapshots and preferences together; the watch sends absolute-count events for strokes, Finish Hole, Pass Hole and Finish Round, falling back to a durable queue when the phone is unreachable.
Theme and preferences One shared theme definition compiled into the iPhone app, watch app and both widget extensions. Preferences are local, versioned, and pushed to the watch.
Widgets and Live Activity Watch complication and Smart Stack (App Group shared state, reload only on visible change); iPhone Live Activity kept in step with the active round.

Engineering Notes — Keeping Every Stroke

A lost or double-counted stroke is the worst bug this app can have. Every new action in 1.2 was added with the same guarantees as stroke counting.

Known Limitations in 1.2

Version History

VersionFocusWhy
1.2 (current) Round experience from golfer feedback: optional par, Pass Hole, Finish Round at any hole (iPhone and Watch); Settings and themes; safer data Real rounds are often 9 holes, skip holes, and ignore par
1.1 Apple Watch Experience: complication, Smart Stack, layouts for every case size, revision-based sync Getting back to the counter from other golf apps was slow; small watches clipped controls
1.0 Initial launch: iPhone + Watch stroke counter, scorecard, history, Live Activity A minimal, offline way to count strokes from the wrist