iOS Dev Weekly — Issue #60
Opening
Between Xcode 27 beta shaking up workflows and another high‑profile App Store review retraction making the rounds, teams are quietly wrestling with a more basic failure mode: app hangs that never crash and never log. SwiftUI and Observation make it easy to trigger extra work on the main thread without noticing, and Time Profiler is still the fastest truth serum we have. This week is about turning “it feels sluggish” into a fix you can ship.
This Week’s Big Story
Diagnosing iOS Hangs with Xcode Time Profiler
Hangs are the ugliest kind of failure because they hide where the time actually goes, usually somewhere on the main thread you didn’t mean to touch. If you can capture a clean Time Profiler run, expand the main thread to your first app frame, and annotate with signposts, you can usually spot the blocking call in minutes. The trick is reading stacks with intent: keep your mental model of what should be off-main, then let the evidence change your mind.
Trend Signals
• Retraction of a widely shared “App Store Rejection of the Week” reminds us to read guidelines and edge cases closely before outrage; review can be correct and still surprising. [Source: HackerNews]
• Klepton shows Android ARM64 VR APKs running on Apple Vision Pro, hinting at a wave of experimental ports and performance benchmarks for 3D/VR pipelines on visionOS. [Source: HackerNews]
• The Swift.org July 2026 roundup suggests steady momentum across tooling, concurrency discussions, and package ecosystem improvements—worth scanning for upcoming source-compat impacts. [Source: Swift.org Blog]
• Xcode 27 (beta 4) appears to be a substantive release with meaningful quality-of-life fixes; teams should budget time to validate build settings, test plans, and new diagnostics. [Source: dev.to]
Swift Snippet of the Week
import SwiftUI
import Foundation
import Observation
import OSLog
struct FeedItem: Identifiable, Decodable, Equatable {
let id: Int
let title: String
}
@MainActor
@Observable
final class FeedModel {
var items: [FeedItem] = []
private let signposter = OSSignposter(subsystem: "com.example.app", category: "Feed")
private let logger = Logger(subsystem: "com.example.app", category: "Feed")
func load() async {
let name: StaticString = "FeedLoad"
let state = signposter.beginInterval(name)
defer { signposter.endInterval(name, state) }
do {
let newItems = try await Self.fetchAndDecodeOffMain()
logger.log("AssignItems.count=\(newItems.count, privacy: .public)")
items = newItems
// … (truncated for newsletter)
This combo—Observation for minimal invalidations, @MainActor for explicit UI hops, and OSSignposter for proof—codifies two hard‑won habits: keep work off the main thread and measure the hot paths you think you fixed.
Community Picks
Retraction: The App Store Rejection of the Week That Was a Correct Rejection — A useful reminder that policy nuance matters; verify before you escalate.
Run Android ARM64 VR APKs on Apple Vision Pro — Not production-ready, but an eye‑opener for performance exploration and cross‑platform rendering assumptions.
Xcode 27: Everything Developers Need to Know — A practical overview to plan your beta adoption and CI breakage budget.
Until Next Time
If you’re chasing a stall, grab a Time Profiler trace on device, read the main-thread stack until you hit your code, and let the data drive the fix. Read the full piece for a battle-tested flow and signposting tips, then hit reply or forward this to the teammate who “just scrolled and it froze.” I’m also comparing notes in the weekly discussion—tell me what actually blocked your main thread and what finally gave it away.