Thorsten Stark

@thostark.bsky.social

iOS Developer since 2009 – doing Swift, SwiftUI, Objc, macOS, UI/UX, CI/CD, git, automation and a bit more. Developer of @batteriesapp.bsky.social

A vertical bar on iPhone Duo has a fixed width, so a long text label has nowhere to grow. Items with an icon go to the vertical axis, text-only items stay horizontal. Set both a title and an image on every toolbar item and let the system pick. #iosdev #iphoneduo

On iPhone Duo an app gets vertical bars only when it rebuilds against the newest SDK and lets a navigation container own its bars. A bar built by hand from UIToolbar, UINavigationBar or UITabBar has its content ignored entirely. The system cannot tell those are bar items. #iosdev #iphoneduo

Opening Batteries At Home with zero devices shows its own screen: one illustration, one headline, one button to add your first device. Everything else in the app only makes sense once a device exists, so that empty screen gets the same design attention as the loaded one. #iosdev #swiftui

iPhone Duo moves navigation, toolbar and tab items into one vertical bar at the edge of the display. A screen that is worse off can opt out: toolbarVerticalBehavior(.disabled) in SwiftUI, preferredVerticalBarBehavior returning .disabled in UIKit. #iosdev #iphoneduo

An iOS widget runs in an extension, and that extension has a much tighter memory budget than an app. Decoding a full resolution photo in a timeline provider may get the process killed. No crash to see, just the placeholder. Downsample before you render. #iosdev #widgetkit

The hardest number in my battery tracker is the first battery in a new device. Two recorded changes in, the next one is arithmetic. A new device has no dates yet. The usual lifetime comes from the average for that battery type in the house, with an indicator for how sure it is. #indiedev #iosdev

@ Observable tracks reads per view. A view is invalidated only by the properties it read in its last body pass. ObservableObject publishes at the object level, so every observing view redraws, whatever changed. Reading a property for a debug print now subscribes you to it. #iosdev #swiftui

Two parents, one timetable, and until now each of them types it in separately. The next update shares a child's schedule with a second iCloud user, read only or with editing. Sharing is Pro, accepting an invitation is not. Not live yet. #backtoschool

The small widget in Batteries At Home used to be a list of rows. It is a 2x2 grid now. Four devices fit, each one a ring: remaining lifetime as the arc, state as the color, the device icon in the middle. Every cell is its own Link, so a tap opens that device. #indiedev #widgetkit

The Predicate macro in SwiftData is not a Swift closure. It is a query builder. Everything in it has to translate into a database query. Computed properties and helper methods do not exist down there, so you get a compile error or a fetch that fails. #iosdev #swiftdata

If two branches of an if render the same view, pass the difference as data instead. @ State is not attached to your view, it is attached to its position in the view tree. Two branches are two identities, and switching between them throws the state away. #swiftui #iosdev

A status screen needs a state for nothing to do, and that state should be the common one. The dashboard in Batteries At Home has four: first run, calm, normal, alarm. Calm means nothing overdue and nothing due within seven days, and it says so instead of ranking devices. #indiedev #swiftui

Your widget can show a live countdown without spending a single timeline reload. Text(date, style: .timer) and ProgressView(timerInterval:) are updated by the system between reloads. Everything else needs a new timeline entry, from a budget you do not control. #iosdev #widgetkit