Post

Replies

Boosts

Views

Activity

Get View Full HDR state from Settings > Photos to properly set preferredImageDynamicRange in editing extension
I'm updating my Photo Editing Extension to support HDR. To do this I set imageView.preferredImageDynamicRange = .high. But you can turn off the option to view HDR photos in the complete dynamic range in Settings > Photos. When you do that, open a photo, and tap the edit button, it does not appear in the full range as expected, but when you select my app from More > Extensions, it does appear in the complete dynamic range unexpectedly. I need to set imageView.preferredImageDynamicRange = .standard when View Full HDR is off, but I don't see any way to get that in my PHContentEditingController.
1
0
688
Oct ’24
How to edit gain map image to preserve HDR in Live Photo
I have an app that allows you to edit your photos. To preserve HDR, I edit both the SDR image and gain map image, like so: let sdrImage = CIImage(data: data, options: [.applyOrientationProperty: true]) let gainMapImage = CIImage(data: data, options: [.applyOrientationProperty: true, .auxiliaryHDRGainMap: true]) // edit them... try CIContext().writeHEIFRepresentation(of: sdrImage, to: url, format: .RGBA8, colorSpace: colorSpace, options: [.hdrGainMapImage: gainMapImage]) I also support editing the still photo in Live Photos. To do this you create a PHLivePhotoEditingContext, set the frameProcessor block which gives you a CIImage that I edit when the frame.type is .photo, then you create a PHContentEditingOutput and call saveLivePhoto. I’m not seeing any way to preserve HDR here. Interestingly the frame processor is called twice with .photo frame.type, but I don’t see any difference between these images. How can I edit a gain map image to preserve HDR in the still photo of a Live Photo?
1
0
815
Nov ’24
Failed to launch Photo Editing Extension from Mac Catalyst app
I have an iOS app that includes a Photo Editing Extension and is optimized for Mac Catalyst so you can edit photos in the Photos app on your Mac. This has worked really well but now I am encountering an error alert trying to open the photo editing extension: RBSLaunchRequest error trying to launch plugin com.company.TestEditor. TestPhotoEditor (B7A616A7-2 5A8-4E02-8B32-5CAB37C8B4B2): ErrorDomain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x7f08fafd0 {ErrorDomain=NSPOSIXErrorDomain Code=153 "Unknown error: 153" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}} Create a new iOS app project in Xcode Create a new target and choose iOS > Photo Editing Extension For both targets in the project, add Mac Catalyst as a supported destination Run the app on My Mac (Mac Catalyst) Open the Photos app, double click a photo, click Edit, click the more plugins button, and click TestPhotoEditor in the list macOS 15.4.1 + Xcode 16.3
1
0
514
May ’25
PHAssetChangeRequest revertAssetContentToOriginal without original asset content
The documentation for PHAssetChangeRequest.revertAssetContentToOriginal says it will fail if the original asset content is not on the current device so you should use PHAssetResourceManager to download it first, but this no longer seems to be the case in the latest iOS versions because an error no longer occurs when I take a photo on my iPhone, edit it, open Photos on my iPad and let it sync, then open my app on iPad and call revertAssetContentToOriginal for that asset. Does the system now take care of downloading the original when needed?
1
0
180
Jun ’25
StoreKit 2: Handle unfinished consumables
I have non-consumable and consumable in-app purchases in my app. The tutorial I was following stated Transaction.currentEntitlements includes unfinished consumables, which is incorrect according to the documentation. Is the correct way to handle unfinished consumables (and non-consumables) to implement Transaction.updates and call finish() if it’s verified? The documentation says that listener will receive unfinished transactions once upon app launch, so with that, do I understand correctly you do not need to implement Transaction.unfinished unless you want to look for unfinished transactions manually later on? Otherwise what is the correct and most recommended way to handle unfinished consumables? Is there a way to test that scenario in Xcode?
1
0
269
Jun ’25
Widget error upon restore iPhone: The file "Name.sqlite" couldn't be opened
I have an app that uses NSPersistentCloudKitContainer stored in a shared location via App Groups so my widget can fetch data to display. It works. But if you reset your iPhone and restore it from a backup, an error occurs: The file "Name.sqlite" couldn't be opened. I suspect this happens because the widget is created before the app's data is restored. Restarting the iPhone is the only way to fix it though, opening the app and reloading timelines does not. Anything I can do to fix that to not require turning it off and on again?
12
0
325
Jul ’25
How to replace layoutManager with textLayoutManager for a flexible dynamic height UITextView
In order to create a UITextView like that of the Messages app whose height grows to fits its contents (number of lines), I subclassed UITextView and customized the intrinsicContentSize like so: override var intrinsicContentSize: CGSize { var size = super.intrinsicContentSize if size.height == UIView.noIntrinsicMetric { layoutManager.glyphRange(for: textContainer) size.height = layoutManager.usedRect(for: textContainer).height + textContainerInset.top + textContainerInset.bottom } return size } As noted at WWDC, accessing layoutManager will force TextKit 1, we should instead use textLayoutManager. How can this code be migrated to support TextKit 2?
3
0
220
Jun ’25
How to initialize OpenIntent parameter when returning OpensIntent in perform
I have an app that lets you create cars. I have a CarEntity, an OpenCarIntent, and a CreateCarIntent. I want to support the Open When Run option when creating a car. I understand to do this, you just update the return type of your perform function to include & OpensIntent, then change your return value to include opensIntent: OpenCarIntent(target: carEntity). When I do this, I get a compile-time error: Cannot convert value of type 'CarEntity' to expected argument type 'IntentParameter<CarEntity>' What am I doing wrong here? struct CreateCarIntent: ForegroundContinuableIntent { static let title: LocalizedStringResource = "Create Car" @Parameter(title: "Name") var name: String @MainActor func perform() async throws -> some IntentResult & ReturnsValue<CarEntity> & OpensIntent { let managedObjectContext = PersistenceController.shared.container.viewContext let car = Car(context: managedObjectContext) car.name = name try await managedObjectContext.perform { try managedObjectContext.save() } let carEntity = CarEntity(car: car) return .result( value: carEntity, opensIntent: OpenCarIntent(target: carEntity) // FIXME: Won't compile ) } } struct OpenCarIntent: OpenIntent { static let title: LocalizedStringResource = "Open Car" @Parameter(title: "Car") var target: CarEntity @MainActor func perform() async throws -> some IntentResult { await UIApplication.shared.open(URL(string: "carapp://cars/view?id=\(target.id)")!) return .result() } }
2
0
224
Jun ’25
How to donate IndexedEntity, if required in iOS 26
In the Get to Know App Intents WWDC session, it was said New this year, you can now add Spotlight indexing keys directly on properties. Annotating properties allows Spotlight to show more relevant information to customers. When donating indexed entities, the framework will handle creating the searchable item and attribute set for you. After donating entities, they can be found in Spotlight. How do you donate indexed app entities? Making app entities available in Spotlight seems to state it's not necessary to donate entities: The system can automatically extract the keys for Spotlight indexing at compile time and store them in the App Intents metadata that Xcode generates as part of your app’s bundle. As a result, Spotlight indexing is faster and can find your app entities without launching your app, and without you having to explicitly donate the entities to Spotlight. You also don’t need to manually update or remove entities from the Spotlight index when your app’s data changes. Say I have a CarEntity. The user can create/update/delete cars at any time. What is the modern way to get cars to appear in Spotlight in iOS 26?
2
0
338
Jun ’25
How to show confirmationDialog from a Button in a Menu
I have a More button in my nav bar that contains a Delete action, and when you tap that I want to show a confirmation dialog before performing the deletion. In order words, I have a toolbar containing a toolbar item containing a menu containing a button that when tapped needs to show a confirmation dialog. In iOS 26, you're supposed to add the confirmationDialog on the view that presents the action sheet so that it can point to the source view or morph out of it if it's liquid glass. But when I do that, the confirmation dialog does not appear. Is that a bug or am I doing something wrong? struct ContentView: View { @State private var showingDeleteConfirmation = false var body: some View { NavigationStack { Text("👋, 🌎!") .toolbar { ToolbarItem { Menu { Button(role: .destructive) { showingDeleteConfirmation.toggle() } label: { Label("Delete", systemImage: "trash") } .confirmationDialog("Are you sure?", isPresented: $showingDeleteConfirmation) { Button(role: .destructive) { print("Delete it") } label: { Text("Delete") } Button(role: .cancel, action: {}) } } label: { Label("More", systemImage: "ellipsis") } } } } } }
1
0
264
Jul ’25
How to hide scroll edge effect until scroll down
I present a view in a sheet that consists of a navigation stack and a scroll view which has a photo pushed to the top by setting .ignoresSafeArea(edges: .top). The problem is the top of the photo is blurry due to the scroll edge effect. I would like to hide the scroll edge effect so the photo is fully visible when scrolled to the top but let the effect become visible upon scrolling down. Is that possible? struct ContentView: View { @State private var showingSheet = false var body: some View { VStack { Button("Present Sheet") { showingSheet = true } } .sheet(isPresented: $showingSheet) { SheetView() } } } struct SheetView: View { @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { ScrollView { VStack { Image("Photo") .resizable() .scaledToFill() } } .ignoresSafeArea(edges: .top) .toolbar { ToolbarItem(placement: .cancellationAction) { Button(role: .close) { dismiss() } } ToolbarItem { EditButton() } } } } }
1
0
214
Jul ’25
Different toolbar item placement for iPhone vs iPad
On iPhone, I would like to have a more button at the top right of the navigation bar, a search field in the bottom toolbar, and a plus button to the right of the search field. I've achieved this via the code below. But on iPad they should be in the navigation bar at the trailing edge from left to right: plus, more, search field. Just like the Shortcuts app, if there's not enough horizontal space, the search field should collapse into a button, and with even smaller space the search bar should become full-width under the navigation bar. Right now on iPad the search bar is full width under the navigation bar, more at top right, plus at bottom middle, no matter how big the window is. How can I achieve that? Any way to specify them for the system to more automatically do the right thing, or would I need to check specifically for iPhone vs iPad UIDevice to change the code? struct ContentView: View { @State private var searchText = "" var body: some View { NavigationStack { VStack { Text("Hello, world!") } .navigationTitle("Test App") .searchable(text: $searchText) .toolbar { ToolbarItem { Menu { //... } label: { Label("More", systemImage: "ellipsis") } } DefaultToolbarItem(kind: .search, placement: .bottomBar) ToolbarSpacer(.fixed, placement: .bottomBar) ToolbarItem(placement: .bottomBar) { Button { print("Add tapped") } label: { Label("Add", systemImage: "plus") } } } } } }
3
0
290
Aug ’25
Get View Full HDR state from Settings > Photos to properly set preferredImageDynamicRange in editing extension
I'm updating my Photo Editing Extension to support HDR. To do this I set imageView.preferredImageDynamicRange = .high. But you can turn off the option to view HDR photos in the complete dynamic range in Settings > Photos. When you do that, open a photo, and tap the edit button, it does not appear in the full range as expected, but when you select my app from More > Extensions, it does appear in the complete dynamic range unexpectedly. I need to set imageView.preferredImageDynamicRange = .standard when View Full HDR is off, but I don't see any way to get that in my PHContentEditingController.
Replies
1
Boosts
0
Views
688
Activity
Oct ’24
How to edit gain map image to preserve HDR in Live Photo
I have an app that allows you to edit your photos. To preserve HDR, I edit both the SDR image and gain map image, like so: let sdrImage = CIImage(data: data, options: [.applyOrientationProperty: true]) let gainMapImage = CIImage(data: data, options: [.applyOrientationProperty: true, .auxiliaryHDRGainMap: true]) // edit them... try CIContext().writeHEIFRepresentation(of: sdrImage, to: url, format: .RGBA8, colorSpace: colorSpace, options: [.hdrGainMapImage: gainMapImage]) I also support editing the still photo in Live Photos. To do this you create a PHLivePhotoEditingContext, set the frameProcessor block which gives you a CIImage that I edit when the frame.type is .photo, then you create a PHContentEditingOutput and call saveLivePhoto. I’m not seeing any way to preserve HDR here. Interestingly the frame processor is called twice with .photo frame.type, but I don’t see any difference between these images. How can I edit a gain map image to preserve HDR in the still photo of a Live Photo?
Replies
1
Boosts
0
Views
815
Activity
Nov ’24
Failed to launch Photo Editing Extension from Mac Catalyst app
I have an iOS app that includes a Photo Editing Extension and is optimized for Mac Catalyst so you can edit photos in the Photos app on your Mac. This has worked really well but now I am encountering an error alert trying to open the photo editing extension: RBSLaunchRequest error trying to launch plugin com.company.TestEditor. TestPhotoEditor (B7A616A7-2 5A8-4E02-8B32-5CAB37C8B4B2): ErrorDomain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x7f08fafd0 {ErrorDomain=NSPOSIXErrorDomain Code=153 "Unknown error: 153" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}} Create a new iOS app project in Xcode Create a new target and choose iOS > Photo Editing Extension For both targets in the project, add Mac Catalyst as a supported destination Run the app on My Mac (Mac Catalyst) Open the Photos app, double click a photo, click Edit, click the more plugins button, and click TestPhotoEditor in the list macOS 15.4.1 + Xcode 16.3
Replies
1
Boosts
0
Views
514
Activity
May ’25
How to calculate smoothness to replicate CALayerCornerCurve.continuous?
iOS 26 added smoothness to CIRoundedRectangleGenerator, for use with CIFilter.roundedRectangleGenerator. What should the smoothness value be to achieve the same corner curve as CALayerCornerCurve.continuous? Does it need to be calculated based on the extent size, if so, how?
Replies
1
Boosts
0
Views
251
Activity
Jun ’25
Editing portrait photo causes CINonLocalizedDescriptionKey error 3
Some users have reported an error editing portrait photo assets in my app: The operation couldn’t be completed. (CINonLocalizedDescriptionKey error 3.) What is that error? Will affected photos always encounter this error (due to data corruption for example) or can it be resolved in a future iOS update? FB16241301
Replies
1
Boosts
0
Views
246
Activity
Jun ’25
PHAssetChangeRequest revertAssetContentToOriginal without original asset content
The documentation for PHAssetChangeRequest.revertAssetContentToOriginal says it will fail if the original asset content is not on the current device so you should use PHAssetResourceManager to download it first, but this no longer seems to be the case in the latest iOS versions because an error no longer occurs when I take a photo on my iPhone, edit it, open Photos on my iPad and let it sync, then open my app on iPad and call revertAssetContentToOriginal for that asset. Does the system now take care of downloading the original when needed?
Replies
1
Boosts
0
Views
180
Activity
Jun ’25
StoreKit 2: Handle unfinished consumables
I have non-consumable and consumable in-app purchases in my app. The tutorial I was following stated Transaction.currentEntitlements includes unfinished consumables, which is incorrect according to the documentation. Is the correct way to handle unfinished consumables (and non-consumables) to implement Transaction.updates and call finish() if it’s verified? The documentation says that listener will receive unfinished transactions once upon app launch, so with that, do I understand correctly you do not need to implement Transaction.unfinished unless you want to look for unfinished transactions manually later on? Otherwise what is the correct and most recommended way to handle unfinished consumables? Is there a way to test that scenario in Xcode?
Replies
1
Boosts
0
Views
269
Activity
Jun ’25
Widget error upon restore iPhone: The file "Name.sqlite" couldn't be opened
I have an app that uses NSPersistentCloudKitContainer stored in a shared location via App Groups so my widget can fetch data to display. It works. But if you reset your iPhone and restore it from a backup, an error occurs: The file "Name.sqlite" couldn't be opened. I suspect this happens because the widget is created before the app's data is restored. Restarting the iPhone is the only way to fix it though, opening the app and reloading timelines does not. Anything I can do to fix that to not require turning it off and on again?
Replies
12
Boosts
0
Views
325
Activity
Jul ’25
How to replace layoutManager with textLayoutManager for a flexible dynamic height UITextView
In order to create a UITextView like that of the Messages app whose height grows to fits its contents (number of lines), I subclassed UITextView and customized the intrinsicContentSize like so: override var intrinsicContentSize: CGSize { var size = super.intrinsicContentSize if size.height == UIView.noIntrinsicMetric { layoutManager.glyphRange(for: textContainer) size.height = layoutManager.usedRect(for: textContainer).height + textContainerInset.top + textContainerInset.bottom } return size } As noted at WWDC, accessing layoutManager will force TextKit 1, we should instead use textLayoutManager. How can this code be migrated to support TextKit 2?
Replies
3
Boosts
0
Views
220
Activity
Jun ’25
How to initialize OpenIntent parameter when returning OpensIntent in perform
I have an app that lets you create cars. I have a CarEntity, an OpenCarIntent, and a CreateCarIntent. I want to support the Open When Run option when creating a car. I understand to do this, you just update the return type of your perform function to include & OpensIntent, then change your return value to include opensIntent: OpenCarIntent(target: carEntity). When I do this, I get a compile-time error: Cannot convert value of type 'CarEntity' to expected argument type 'IntentParameter<CarEntity>' What am I doing wrong here? struct CreateCarIntent: ForegroundContinuableIntent { static let title: LocalizedStringResource = "Create Car" @Parameter(title: "Name") var name: String @MainActor func perform() async throws -> some IntentResult & ReturnsValue<CarEntity> & OpensIntent { let managedObjectContext = PersistenceController.shared.container.viewContext let car = Car(context: managedObjectContext) car.name = name try await managedObjectContext.perform { try managedObjectContext.save() } let carEntity = CarEntity(car: car) return .result( value: carEntity, opensIntent: OpenCarIntent(target: carEntity) // FIXME: Won't compile ) } } struct OpenCarIntent: OpenIntent { static let title: LocalizedStringResource = "Open Car" @Parameter(title: "Car") var target: CarEntity @MainActor func perform() async throws -> some IntentResult { await UIApplication.shared.open(URL(string: "carapp://cars/view?id=\(target.id)")!) return .result() } }
Replies
2
Boosts
0
Views
224
Activity
Jun ’25
How to donate IndexedEntity, if required in iOS 26
In the Get to Know App Intents WWDC session, it was said New this year, you can now add Spotlight indexing keys directly on properties. Annotating properties allows Spotlight to show more relevant information to customers. When donating indexed entities, the framework will handle creating the searchable item and attribute set for you. After donating entities, they can be found in Spotlight. How do you donate indexed app entities? Making app entities available in Spotlight seems to state it's not necessary to donate entities: The system can automatically extract the keys for Spotlight indexing at compile time and store them in the App Intents metadata that Xcode generates as part of your app’s bundle. As a result, Spotlight indexing is faster and can find your app entities without launching your app, and without you having to explicitly donate the entities to Spotlight. You also don’t need to manually update or remove entities from the Spotlight index when your app’s data changes. Say I have a CarEntity. The user can create/update/delete cars at any time. What is the modern way to get cars to appear in Spotlight in iOS 26?
Replies
2
Boosts
0
Views
338
Activity
Jun ’25
System close and prominent done buttons in SwiftUI
How do you create a toolbar item using the standard system close button or prominent done (✔️) button in SwiftUI? In UIKit UIBarButtonItem provides .close and .done system items, and to get the tinted checkmark for done you set style = .prominent.
Replies
2
Boosts
0
Views
236
Activity
Jul ’25
How to show confirmationDialog from a Button in a Menu
I have a More button in my nav bar that contains a Delete action, and when you tap that I want to show a confirmation dialog before performing the deletion. In order words, I have a toolbar containing a toolbar item containing a menu containing a button that when tapped needs to show a confirmation dialog. In iOS 26, you're supposed to add the confirmationDialog on the view that presents the action sheet so that it can point to the source view or morph out of it if it's liquid glass. But when I do that, the confirmation dialog does not appear. Is that a bug or am I doing something wrong? struct ContentView: View { @State private var showingDeleteConfirmation = false var body: some View { NavigationStack { Text("👋, 🌎!") .toolbar { ToolbarItem { Menu { Button(role: .destructive) { showingDeleteConfirmation.toggle() } label: { Label("Delete", systemImage: "trash") } .confirmationDialog("Are you sure?", isPresented: $showingDeleteConfirmation) { Button(role: .destructive) { print("Delete it") } label: { Text("Delete") } Button(role: .cancel, action: {}) } } label: { Label("More", systemImage: "ellipsis") } } } } } }
Replies
1
Boosts
0
Views
264
Activity
Jul ’25
How to hide scroll edge effect until scroll down
I present a view in a sheet that consists of a navigation stack and a scroll view which has a photo pushed to the top by setting .ignoresSafeArea(edges: .top). The problem is the top of the photo is blurry due to the scroll edge effect. I would like to hide the scroll edge effect so the photo is fully visible when scrolled to the top but let the effect become visible upon scrolling down. Is that possible? struct ContentView: View { @State private var showingSheet = false var body: some View { VStack { Button("Present Sheet") { showingSheet = true } } .sheet(isPresented: $showingSheet) { SheetView() } } } struct SheetView: View { @Environment(\.dismiss) private var dismiss var body: some View { NavigationStack { ScrollView { VStack { Image("Photo") .resizable() .scaledToFill() } } .ignoresSafeArea(edges: .top) .toolbar { ToolbarItem(placement: .cancellationAction) { Button(role: .close) { dismiss() } } ToolbarItem { EditButton() } } } } }
Replies
1
Boosts
0
Views
214
Activity
Jul ’25
Different toolbar item placement for iPhone vs iPad
On iPhone, I would like to have a more button at the top right of the navigation bar, a search field in the bottom toolbar, and a plus button to the right of the search field. I've achieved this via the code below. But on iPad they should be in the navigation bar at the trailing edge from left to right: plus, more, search field. Just like the Shortcuts app, if there's not enough horizontal space, the search field should collapse into a button, and with even smaller space the search bar should become full-width under the navigation bar. Right now on iPad the search bar is full width under the navigation bar, more at top right, plus at bottom middle, no matter how big the window is. How can I achieve that? Any way to specify them for the system to more automatically do the right thing, or would I need to check specifically for iPhone vs iPad UIDevice to change the code? struct ContentView: View { @State private var searchText = "" var body: some View { NavigationStack { VStack { Text("Hello, world!") } .navigationTitle("Test App") .searchable(text: $searchText) .toolbar { ToolbarItem { Menu { //... } label: { Label("More", systemImage: "ellipsis") } } DefaultToolbarItem(kind: .search, placement: .bottomBar) ToolbarSpacer(.fixed, placement: .bottomBar) ToolbarItem(placement: .bottomBar) { Button { print("Add tapped") } label: { Label("Add", systemImage: "plus") } } } } } }
Replies
3
Boosts
0
Views
290
Activity
Aug ’25