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.