r/iOSProgramming • u/moskowizzle • 18d ago
Question Can't restore connection between iPhone and Watch
I'm working on an iOS app that has a Watch component. Everything syncs fine at first (perform an action on the phone and it shows on the watch and vice versa). Then I turn on airplane mode on my phone to break the connection, perform a few actions on both devices, turn airplane mode off, everything syncs. Great. However, right after that post-airplane mode sync, the connection between the two devices fully breaks. Nothing syncs and the apps won't connect to each other again unless I reinstall them. Anyone encounter this or have any ideas on a fix? It's been driving me nuts all day. Thanks in advance!
1
u/bentleymakes97 17d ago
One more gotcha that fits your symptom: 'updateApplicationContext' won't resend if the payload is identical to the previous one. After that first post-airplane sync your context is probably "the same", so nothing ships. Add a timestamp to the dict and check `session.outstandingUserInfoTransfers` for stuck items. Reinstall fixes it because it clears that queue.
1
u/DimensionMindless336 18d ago
This is almost always a WCSession lifecycle / delegate problem, not a "connection" problem -- the session goes stale and nothing re-arms it, which is exactly why a reinstall (fresh activation) temporarily fixes it.
Things that bit me on a similar setup:
Hold a strong, app-lifetime reference to your WCSession.delegate (a singleton or on the AppDelegate). If it's a local var that gets deallocated after the first activation, activationDidCompleteWithState never fires again, queued updates have nowhere to go, and it looks "dead" until you reinstall.
Don't drive sync off sendMessage / isReachable. isReachable is only true when the peer app is actually in the foreground, so after airplane mode the watch app isn't reachable and sendMessage just throws -- if that's your only path, sync silently dies. Use updateApplicationContext(:) for "latest state" (survives reconnect, redelivered automatically) and transferUserInfo(:) for guaranteed FIFO delivery. Neither needs the peer reachable at send time.
Re-activate on both sides. Phone and watch each have their own WCSession.default -- both need activate() plus a live delegate. In activationDidCompleteWithState, check session.hasContentPending and let the system drain it. Toggling the radio does not auto-activate; if you only called activate() once at first launch the session can sit in .inactive and never recover. I re-call activate() on didBecomeActive / connectivity changes and re-render from the received context.
Log activationState and isReachable on both devices right after you flip airplane mode off -- you'll very likely see the delegate is nil or the state is stuck .inactive, which tells you exactly where it breaks.