Articles Projects About Subscribe
← All issues Newsletter

iOS Dev Weekly — Issue #68

Opening

Swift Concurrency is mainstream now, and with it comes a new class of lifecycle bugs that feel invisible until Instruments shows a graph that never goes to zero. Teams are realizing actors don’t manage ownership for you — tasks, timers, and closures do. This week is about making those lifecycles explicit and provable.


This Week’s Big Story

Prevent Retain Cycles in Swift Actors

Actors make race conditions vanish, but they won’t manage object graphs for you. Subtle retain cycles can pin actors in memory long after a feature ends, especially when tasks, timers, or closures capture self under the hood. The fixes are design choices: who owns cancellation, how termination happens, and how you prove it in tests and profiling — dig into the article for concrete patterns and instrumentation.


Trend Signals

• Show HN: Kadō — a clean, open-source habit tracker experimenting with a non-binary habit score that could inspire more nuanced progress models in health/productivity apps. [Source: HackerNews]

• What’s new in Swift: August 2026 Edition — the project spotlights Swift’s momentum for web scenarios, which signals ongoing investment in Swift beyond Apple platforms and more shared code opportunities. [Source: Swift.org Blog]

• How to Build an iPhone App With Claude Without Writing Code — early no‑code AI workflows are surfacing; useful for prototypes, but teams should gatekeep production with review, tests, and threat modeling. [Source: Medium]

• AppDelegate vs SceneDelegate in Modern iOS — a timely refresher as multi-window and scene restoration remain sharp edges in real apps, especially with deep links and external displays. [Source: dev.to]

• Copy‑on‑Write Isn’t Free — a good reminder that value semantics don’t waive performance, so profile copies and be honest about large CoW structures in hot paths. [Source: Medium]


Swift Snippet of the Week

import Foundation
import OSLog

actor Heartbeat {
    private let logger = Logger(subsystem: "com.example.Heartbeat", category: "lifecycle")
    private let signposter = OSSignposter()
    private var heartbeatTask: Task<Void, Never>?
    private(set) var beats: Int = 0

    func start() {
        guard heartbeatTask == nil else { return }
        heartbeatTask = Task { [weak self] in
            let state = self?.signposter.beginInterval("heartbeat-loop")
            defer { if let state { self?.signposter.endInterval("heartbeat-loop", state) } }
            while !Task.isCancelled {
                try? await Task.sleep(for: .seconds(1))
                await self?.tick()
            }
        }
    }

    func stop() {
        heartbeatTask?.cancel()
        heartbeatTask = nil
    }
// … (truncated for newsletter)

This pattern keeps cancellation colocated with creation and weakly captures the actor to avoid accidental self-retention, while signposting gives you proof in Instruments that the loop really stops.


Community Picks

Show HN: Kadō – open-source habit tracker, with non-binary habit score, for iOS — Worth a look for data modeling and SwiftUI structure; the scoring approach could translate to streaks without brittleness.

How to Build an iPhone App With Claude Without Writing Code — Fun for ideation; keep a human in the loop for entitlements, privacy, and performance.

AppDelegate vs SceneDelegate in Modern iOS — A concise recap to reduce lifecycle drift and centralize responsibilities the right way.


Until Next Time

If you’re adopting actors at scale, the memory story is as important as the concurrency story — read the piece and tighten your cancellation strategy. I’d love your take: hit reply, forward this to the teammate who owns your async layer, and jump into the LinkedIn thread to share what you’ve measured in Instruments. Let me know what you want covered next.