Articles Projects About Subscribe
← All issues Newsletter

iOS Dev Weekly — Issue #54

Opening

macOS teams are quietly relearning that “window closed” isn’t “objects released.” AppKit happily keeps whole controller trees alive if you give it a single strong edge, and the symptoms only show up under load: scrolling hitching, caches that never empty, and slow leaks that pass smoke tests. This week is about turning Memory Graph snapshots into fixes you can trust in production.


This Week’s Big Story

Hunting AppKit Retain Cycles with Memory Graph

Windows that visually dismiss but stick around are almost always one forgotten observer, timer, or closure away from a leak. Memory Graph shows you the actual owning path; the real craft is wiring predictable teardown so the same bug can’t creep back. If you’ve ever watched an NSTableView get choppy after “closing” a window, this one will pay for itself.


Trend Signals

• What’s new in Swift: June 2026 Edition — Worth a careful read for toolchain and language evolution that will impact migration plans this quarter. [Source: Swift.org Blog]

• UITableView Performance Optimization Techniques — Still relevant in 2026: cell reuse, prefetching, and measuring bottlenecks before “optimizing.” [Source: dev.to]

• Are conditional view modifiers a good idea in SwiftUI? — A useful lens on readability versus flexibility when conditionally composing views. [Source: Medium]

• NyaruDB2: an embedded document database for Swift — Early signals suggest a pragmatic alternative when Core Data is too heavy and SQLite too low-level. [Source: dev.to]


Swift Snippet of the Week

import AppKit

final class ListViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
    private let tableView = NSTableView()
    private var notificationToken: NSObjectProtocol?
    private weak var refreshTimer: Timer?
    private var items: [String] = (0..<1_000).map { "Row \($0)" } // large data to make leaks obvious

    override func loadView() {
        let scroll = NSScrollView()
        scroll.documentView = tableView
        tableView.addTableColumn(NSTableColumn(identifier: .init("main")))
        tableView.headerView = nil
        tableView.delegate = self
        tableView.dataSource = self
        self.view = scroll
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        notificationToken = NotificationCenter.default.addObserver(
            forName: NSApplication.didBecomeActiveNotification,
            object: nil,
            queue: .main
// … (truncated for newsletter)

This pattern puts the usual leak culprits on display—runloop timers and notification tokens—so you remember to design explicit teardown paths (not just deinit) and keep ownership edges visible when debugging AppKit views under load.


Community Picks

iOS 4.23 — Skim for version notes that may affect feature flags or rollout plans.

UITableView Performance Optimization Techniques — A solid checklist to revisit before blaming the network or layout engine.

Are conditional view modifiers a good idea in SwiftUI? — Handy framing for when an if/else reads cleaner than a custom ViewModifier.


Until Next Time

If your AppKit windows “close” but memory doesn’t, the Big Story walks through turning Memory Graph evidence into fixes you can regression-test. Read it, forward to the teammate who owns your table/collection adapters, and then hit reply with what you find in your graphs. I’ll keep the conversation going on LinkedIn—bring your nastiest retain-cycle war stories.