Adapting a large UIKit/Objective-C document viewer controller for iPhone Duo on the iOS 27.1 SDK

We ship a mature document viewer (PDF) written mostly in Objective-C with UIKit. It runs on iPhone and iPad and supports multiple scenes. We're planning support for iPhone Duo and would like advice on the right architectural approach before we start.

Current structure (simplified)

  • One root viewer view controller (a UIViewController subclass, large and long-lived) owns the document view, search, bookmarks, text-to-speech, presentation mode and similar features. Most of these live in categories and helper modules.
  • Chrome is swapped by size class. A factory picks one of two "toolbars controller" classes based on the trait collection: one for compact, one for regular. The regular one also hosts a tab strip and a sidebar built on the system sidebar UI. When the class it would pick changes, traitCollectionDidChange: tears down the current chrome controller, builds the other one, re-parents the document view into the new container, and then restores tool and presentation state. We skip this while the app isn't active, because UIKit sends trait changes during backgrounding.
  • Geometry changes go through viewWillTransitionToSize:withTransitionCoordinator:, which forwards to the chrome controller, the document view and a zoomed handwriting helper. When the transition completes we recompute content insets and re-render the output for an external display.
  • The document view is a custom scroll-based view (not PDFKit). It has display modes for continuous, single page, two-page spread and two-page spread with a cover page. It calculates its own insets from safe areas and whatever chrome is visible.
  • We still use traitCollectionDidChange: and haven't moved to registerForTraitChanges:.

Questions

  1. Posture changes and size-class flips. When the device folds or unfolds, should we expect a normal viewWillTransitionToSize: plus a trait change (compact ↔ regular) that our existing swap handles? Or is there a posture/display-configuration signal we should observe instead? Swapping the whole chrome hierarchy in the middle of a fold animation seems costly. Is there a recommended way to defer or coordinate that with the transition coordinator?
  2. Hinge or seam area. Is the fold region exposed through safe-area insets, layout guides or a new API? A custom scroll view that lays out two-page spreads needs to keep content out of that region, or line the spread up with it. What's the recommended way to get this geometry from Objective-C?
  3. Two-page spread tied to posture. Showing a two-page spread automatically when the device is unfolded (like an open book) seems natural. Does Apple recommend deciding this from traits/posture or from bounds, and is there a trait we can override per view controller?
  4. Trait registration. For this form factor, is it effectively required to move from traitCollectionDidChange: to registerForTraitChanges: (for example to get notified about new traits), or will the legacy callback still fire reliably?
  5. Scenes and external displays. Does iPhone Duo change anything about scene activation, window geometry or UIScreen handling that a multi-scene app with external-display output should plan for?
  6. Incremental adoption. Can we adopt this step by step in Objective-C, or do some of the APIs only exist in Swift and push us toward Swift wrappers?

Any pointers to WWDC sessions, sample code or documentation for adapting existing UIKit apps would be very helpful. Thanks!

Answered by Frameworks Engineer in 906743022

Hi There!

Posture changes and size-class flips. When the device folds or unfolds, should we expect a normal viewWillTransitionToSize: plus a trait change (compact ↔ regular) that our existing swap handles

There's a reason we've been mentioning APIs like these for the last few years:

https://developer.apple.com/videos/play/wwdc2025/282/

https://developer.apple.com/videos/play/wwdc2026/278/

Its because it is the same mechanism on iPhone Duo. As mentioned in "Prepare your app for iPhone Duo", if your iPhone app can resize in iPhone Mirroring, or it is a Universal App that resizes on iPad, you should be in a great place:

https://developer.apple.com/videos/play/tech-talks/111461/

Or is there a posture/display-configuration signal we should observe instead?

Just like with connected external displays on iPad, windowScene(_:didUpdateEffectiveGeometry:) is guaranteed to be called when your UIWindowScene moves between screens:

https://developer.apple.com/documentation/uikit/uiwindowscenedelegate/windowscene(_:didupdateeffectivegeometry:)

However, that's really not the best way to think about responding to the different configurations of the device.

I'd recommend the video "Strike a pose with adaptive layouts on iPhone Duo" for that:

https://developer.apple.com/videos/play/tech-talks/111463/

Hinge or seam area. Is the fold region exposed through safe-area insets, layout guides or a new API?

See the same video I linked above, "Strike a pose with adaptive layouts on iPhone Duo". The best approach here is to first ensure you can handle and layout for size of scene. After that, the video will walk you through how to think about "displacement" and when to employ that.

You might find that built-in containers are all you need, as most already automatically respond in a consistent way across the system. But for custom split view or overlay views, ArrangementView and UIArrangementViewController will also automatically respond to the fold.

If you have targeted things that are manually positioned that you want to adapt to the fold, you can do that with the Reserved Region API.

The common thing here is that all of these are layout-time decisions, and that's key. It makes it easy to adopt these APIs and not have bespoke code for iPhone Duo. For instance, you query the Reserved Regions during layout, and through observation tracking, it will re-trigger layout when they change. There are simply more regions to be interested in for iPhone Duo, but the same API is functional on all other iPhones and iPads.

Two-page spread tied to posture.

Watch the video above, but this sounds like a great opportunity for ArrangementView or UIArrangementViewController.

Trait registration. For this form factor, is it effectively required to move from traitCollectionDidChange: to registerForTraitChanges: (for example to get notified about new traits), or will the legacy callback still fire reliably?

It is always a good idea to move off of deprecated API, but this should behave the same as it does on other phones and iPads running iOS 27.0.

Scenes and external displays. Does iPhone Duo change anything about scene activation, window geometry or UIScreen handling that a multi-scene app with external-display output should plan for?

If you have a camera experience as a part of your app, you can look into the new CameraCaptureAccessory API that allows you to present scenes on both screens at the same time:

https://developer.apple.com/documentation/avfoundation/registering-a-camera-capture-accessory-on-iphone-duo

Otherwise, if you are already handling external display output on iPad, you should be in a good place.

Incremental adoption. Can we adopt this step by step in Objective-C, or do some of the APIs only exist in Swift and push us toward Swift wrappers?

There are some differences between the Objective-C and Swift APIs, but everything should be available in Objective-C.

One final thing I'd mention is looking at the App Resizability skill:

https://developer.apple.com/videos/play/tech-talks/111461/?time=566

This skill will go over your code and help you update to best practices so that your app is ready for iPhone Duo.

Hope that helps!

Accepted Answer

Hi There!

Posture changes and size-class flips. When the device folds or unfolds, should we expect a normal viewWillTransitionToSize: plus a trait change (compact ↔ regular) that our existing swap handles

There's a reason we've been mentioning APIs like these for the last few years:

https://developer.apple.com/videos/play/wwdc2025/282/

https://developer.apple.com/videos/play/wwdc2026/278/

Its because it is the same mechanism on iPhone Duo. As mentioned in "Prepare your app for iPhone Duo", if your iPhone app can resize in iPhone Mirroring, or it is a Universal App that resizes on iPad, you should be in a great place:

https://developer.apple.com/videos/play/tech-talks/111461/

Or is there a posture/display-configuration signal we should observe instead?

Just like with connected external displays on iPad, windowScene(_:didUpdateEffectiveGeometry:) is guaranteed to be called when your UIWindowScene moves between screens:

https://developer.apple.com/documentation/uikit/uiwindowscenedelegate/windowscene(_:didupdateeffectivegeometry:)

However, that's really not the best way to think about responding to the different configurations of the device.

I'd recommend the video "Strike a pose with adaptive layouts on iPhone Duo" for that:

https://developer.apple.com/videos/play/tech-talks/111463/

Hinge or seam area. Is the fold region exposed through safe-area insets, layout guides or a new API?

See the same video I linked above, "Strike a pose with adaptive layouts on iPhone Duo". The best approach here is to first ensure you can handle and layout for size of scene. After that, the video will walk you through how to think about "displacement" and when to employ that.

You might find that built-in containers are all you need, as most already automatically respond in a consistent way across the system. But for custom split view or overlay views, ArrangementView and UIArrangementViewController will also automatically respond to the fold.

If you have targeted things that are manually positioned that you want to adapt to the fold, you can do that with the Reserved Region API.

The common thing here is that all of these are layout-time decisions, and that's key. It makes it easy to adopt these APIs and not have bespoke code for iPhone Duo. For instance, you query the Reserved Regions during layout, and through observation tracking, it will re-trigger layout when they change. There are simply more regions to be interested in for iPhone Duo, but the same API is functional on all other iPhones and iPads.

Two-page spread tied to posture.

Watch the video above, but this sounds like a great opportunity for ArrangementView or UIArrangementViewController.

Trait registration. For this form factor, is it effectively required to move from traitCollectionDidChange: to registerForTraitChanges: (for example to get notified about new traits), or will the legacy callback still fire reliably?

It is always a good idea to move off of deprecated API, but this should behave the same as it does on other phones and iPads running iOS 27.0.

Scenes and external displays. Does iPhone Duo change anything about scene activation, window geometry or UIScreen handling that a multi-scene app with external-display output should plan for?

If you have a camera experience as a part of your app, you can look into the new CameraCaptureAccessory API that allows you to present scenes on both screens at the same time:

https://developer.apple.com/documentation/avfoundation/registering-a-camera-capture-accessory-on-iphone-duo

Otherwise, if you are already handling external display output on iPad, you should be in a good place.

Incremental adoption. Can we adopt this step by step in Objective-C, or do some of the APIs only exist in Swift and push us toward Swift wrappers?

There are some differences between the Objective-C and Swift APIs, but everything should be available in Objective-C.

One final thing I'd mention is looking at the App Resizability skill:

https://developer.apple.com/videos/play/tech-talks/111461/?time=566

This skill will go over your code and help you update to best practices so that your app is ready for iPhone Duo.

Hope that helps!

Adapting a large UIKit/Objective-C document viewer controller for iPhone Duo on the iOS 27.1 SDK
 
 
Q