In didFinishLaunchingWithOptions I have this setup for getting the token to send to my server for notifications. The issue is that the delegate callback didRegisterForRemoteNotificationsWithDeviceToken gets called twice when also initializing a CKSyncEngine object.
This confuses me. Is this expected behavior? Why is the delegate callback only called twice when both are called, but not at all when only using CKSyncEngine.
See code and comments below.
/// Calling just this triggers `didRegisterForRemoteNotificationsWithDeviceToken` once.
UIApplication.shared.registerForRemoteNotifications()
/// When triggering the above function plus initializing a CKSyncEngine, `didRegisterForRemoteNotificationsWithDeviceToken` gets called twice.
/// This somewhat make sense, because CloudKit likely also registers for remote notifications itself, but why is the delegate not triggered when *only* initializing CKSyncEngine and removing the `registerForRemoteNotifications` call above?
let syncManager = SyncManager()
/// Further more, if calling `registerForRemoteNotifications` with a delay instead of directly, the delegate is only called once, as expected. For some reason, the delegate is only triggered when two entities call `registerForRemoteNotifications` at the same time?
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
UIApplication.shared.registerForRemoteNotifications()
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("didRegisterForRemoteNotificationsWithDeviceToken")
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Filed as FB20766506
I have a very simple use case for a rectangular widget on the iPhone lock screen: One Text element which should fill as much space as possible. However, it only ever does 2 per default and then eclipses the rest of the string.
Three separate Text elements work fine, so does a fixedSize modifier hack (with that even four lines are possible!). Am I completely misunderstanding something or why is this not possible per default? Other apps' widgets like Health do it as well.
My attempt (background added for emphasis)
Health app widget
var body: some View {
VStack(alignment: .leading) {
/// This should span three lines, but only spans 2 which eclipsed text.
Text("This is a very long text which should span multiple lines.")
// .fixedSize(horizontal: false, vertical: true) /// Using this fixes it as well, but that does not seem like a good default solution.
/// Three separate `Text` elements work fine.
// Text("This is a very long")
// Text("text which should")
// Text("span multiple lines.")
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(Color.black) /// Added for emphasis of the widget frame
}
Call Screening has serious issues right now leading to missing calls from genuine callers because the system does not acknowledge them with missed call notifications or badges in a lot of cases. I'm posting this in the hope of catching an engineer who can bring this to the attention of the teams working on this.
Filed as FB20678829
—
I ran the following tests with iOS 26.1 beta 3, but the issues have been occurring on iOS 26.0 as well.
I used an iPhone, Apple Watch, iPad, and Mac for this.
The iPhone has Call Screening enabled with the option „Ask Reason for Calling“
The iPhone has call forwarding enabled to all devices.
Test 1: Active Focus
Turn on a focus like Do not Disturb on all devices.
Lock all devices.
Make a phone call to the iPhone with an unknown number.
Behavior:
iPhone: displays Call Screening UI on the Lock Screen, but it will not light up the screen. You don’t know Call Screening is happening unless you activate the display just in that moment on devices without Always On Display.
Watch: does nothing.
Mac: does nothing.
iPad: displays Call Screening UI on the Lock Screen, but it will not light up the screen. You don’t know Call Screening is happening unless you activate the display just in that moment.
In this test the caller does not answer any of the Call Screening questions and just hangs up. The result is that only the Mac displays a missed call notification. iPhone, iPad, and Watch do not acknowledge the missed call (no phone app icon badge, no notification, no badge inside the Phone app itself), you can only see the call inside the Calls list when manually looking for it.
Test 2: No Focus
Turn off any focus like Do not Disturb on all devices.
Lock all devices.
Make a phone call to the iPhone with an unknown number.
Behavior:
iPhone: displays Call Screening UI on the Lock Screen, but it will not light up the screen. You don’t know Call Screening is happening unless you activate the display just in that moment on devices without Always On Display.
Watch: does nothing.
Mac: displays Call Screening UI when unlocked.
iPad: displays Call Screening UI on the Lock Screen, but it will not light up the screen. You don’t know Call Screening is happening unless you activate the display just in that moment.
In this test the caller does not answer any of the Call Screening questions and just hangs up. The result is that only the Mac displays a missed call notification. iPhone, iPad, and Watch do not acknowledge the missed call (no phone app icon badge, no notification, no badge inside the Phone app itself), you can only see the call inside the Calls list when manually looking for it. The only improvement here is that the Mac now shows the Call Screening UI.
Test 3: Caller answers Call Screening questions
An active focus does not matter.
Lock all devices.
Make a phone call to the iPhone with an unknown number.
Once the caller answered the Call Screening questions, the following happens:
All devices ring like expected
When the caller hangs up or I don’t answer:
Mac: Shows Missed Call notification without details
iPhone: Shows Missed Call notification with transcript of Call Screening (also badges phone app icon)
iPad: does nothing.
Watch: Shows the mirrored iPhone notification.
Things to note:
When turning off call forwarding on iPhone to other Apple devices like iPad and Mac, the phone app icon is always badged for missed calls when Call Screening was active, but no notification is displayed regardless.
I'm running a project with these settings:
Default Actor Isolation: MainActor
Approachable Concurrency: Yes
Strict Concurrency Checking: Complete (this issue does not appear on the other two modes)
I receive a warning for this very simple use case. Can I actually fix anything about this or is this a case of Core Data not being entirely ready for this?
In reference to this, there was a workaround listed in the release notes of iOS 26 beta 5 (https://forums.swift.org/t/defaultisolation-mainactor-and-core-data-background-tasks/80569/22). Does this still apply as the only fix for this?
This is a simplified sample meant to run on a background context. The issue obviously goes away if this function would just run on the MainActor, then I can remove the perform block entirely.
class DataHandler {
func createItem() async {
let context = ...
await context.perform {
let newGame = Item(context: context)
/// Main actor-isolated property 'timestamp' can not be mutated from a Sendable closure
newGame.timestamp = Date.now
// ...
}
}
}
The complete use case would be more like this:
nonisolated
struct DataHandler {
@concurrent
func saveItem() async throws {
let context = await PersistenceController.shared.container.newBackgroundContext()
try await context.perform {
let newGame = Item(context: context)
newGame.timestamp = Date.now
try context.save()
}
}
}
If you use UISceneDelegate's scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) to handle deep links (such as tapping a widget) you might run into an issue where this callback is called twice in the majority of cases.
If you push a view controller in response to this, you might end up with two pushed view controllers, if you do not mitigate this. This is exclusively an issue in iOS 26.0 and works as expected on iOS 18.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
/// Add any widget to the home screen that uses the widgetURL modifier and tap them. Most of the time, openURLContexts() will get called twice.
/// If you run this project on iOS 18, it's *always* called once as expected.
print("openURLContexts \(URLContexts)")
}
Filed as FB20301454
I want the gray view to have concentric corners with the device border. That works. Then I want the blue rectangle to have concentric corners with the gray view. That does not work. Instead the blue rectangle is also concentric with the device border. Once I add other content like a Text element, the corner radius breaks.
How can I make this work? .containerShape does not take a ConcentricContainerShape.
struct ContentView: View {
var body: some View {
List {
Text("Content")
}
.overlay(alignment: .bottom) {
content
}
.ignoresSafeArea(.all, edges: .bottom)
}
var content: some View {
VStack(alignment: .leading) {
Rectangle()
.foregroundStyle(.blue)
.frame(width: 100, height: 100)
.clipShape(.rect(corners: .concentric, isUniform: true))
Text("Custom Container")
}
.padding(20)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.gray, in: .rect(corners: .concentric, isUniform: true))
.padding(15)
}
}
This app icon features multiple layers with the blend mode set to Screen. iOS fails to render these despite looking perfectly fine in Icon Composer.
This is unacceptable. How can a designer build an icon if they can't rely on it being displayed like the preview on a device?
Filed as FB20052048 with the .icon file attached.
At WWDC the scroll edge effect was presented as a variable blur combined with a soft gradient.
Since beta 4 the bottom scroll edge effect has no blur, the top bar sometimes has, but sometimes does not. Even in my own app I have two views with totally different results. This was not changed back in beta 5, so I assume this is not a bug but an intended change.
It's hard to design for such a moving target. Especially the missing bottom blur looks bad in a lot of places in my app and I'm debating not shipping the new design if this does not get resolved.
Is there any guidance how this effect is supposed to look now? At this point it just seems random and there's no way adjust the way it looks.
Phone: Top blur, bottom no blur
Settings: Top blur, bottom no blur
Notes: No blur at all
Music: No blur at all
My own app: No top blur
My own app: Top blur
As of right now Icon Composer does not support creating app icons for visionOS and tvOS. It appears that only system apps can provide glass icons for those platforms. How should developers handle this? In extreme cases, the flat icon on those platforms will look wildly different from their glass counterparts.
From what I have seen visionOS and tvOS also do not apply any automatic treatment like on iOS where legacy icons get a glass effect.
So, third party app icons are just going to look out of place for (hopefully just) a year on those platforms? What is the recommended approach here? You could obviously fake the effect, but I feel like that would be worse.
In a UIKit-based project, I am attempting to integrate SwiftUI components. However, I encounter a persistent issue that hinders this integration.
This problem arises when pushing a SwiftUI view using UIHostingController and subsequently attempting to push a UIKit view controller using UIViewControllerRepresentable. Not only are the navigation items and title from the view controller disregarded, but more concerningly, my tab bar item title is set to nil. This renders it impossible for me to utilize SwiftUI within my application when I wish to present older UIKit view controllers from there.
This feedback has all the details and a sample project.
FB18956999
@MainActor
class KeyboardObserver {
var token: NotificationCenter.ObservationToken!
func registerObserver(screen: UIScreen) {
let center = NotificationCenter.default
token = center.addObserver(of: screen, for: .keyboardWillShow) { keyboardState in
print("+++ Keyboard showed up!")
}
}
}
The notification is never called.
The sample code from the sessions also does not work for me.
let keyboardObserver = NotificationCenter.default.addObserver(
of: UIScreen.self
for: .keyboardWillShow
) { message in
UIView.animate(
withDuration: message.animationDuration, delay: 0, options: .flushUpdates
) {
// Use message.endFrame to animate the layout of views with the keyboard
let keyboardOverlap = view.bounds.maxY - message.endFrame.minY
bottomConstraint.constant = keyboardOverlap
}
}
@MainActor
class KeyboardObserver {
func registerObserver(screen: UIScreen) {
let center = NotificationCenter.default
let token = center.addObserver(
of: screen,
for: .keyboardWillShow
) { keyboardState in
let startFrame = keyboardState.startFrame
let endFrame = keyboardState.endFrame
self.keyboardWillShow(startFrame: startFrame, endFrame: endFrame)
}
}
func keyboardWillShow(startFrame: CGRect, endFrame: CGRect) {}
}
I'm using a standard UITabBarController on iPad. When first selecting any tab, the corresponding menu bar items are grayed out for this view controller. It's only when I tap any button in that view controller, like in the toolbar, that the view controller truly becomes the first responder (you can see the sidebar selection turns to gray from blue), enabling those menu bar items.
Am I doing something wrong here?
A video of the issue can be found here: https://mastodon.social/@nicoreese/114949924393554961
AppDelegate:
...
builder.insertChild(MenuController.viewModeMenu(), atStartOfMenu: .view)
class func viewModeMenu() -> UIMenu {
let listViewModeCommand = UICommand(
title: String(localized: "As List"),
image: UIImage(systemName: "list.bullet"),
action: #selector(GamesViewController.setListViewMode),
propertyList: SettingsService.ViewMode.list.rawValue
)
...
let viewModeMenu = UIMenu(
title: "",
image: nil,
identifier: .viewModeMenu,
options: .displayInline,
children: [listViewModeCommand...]
)
return viewModeMenu
}
GamesViewController:
@objc
func setListViewMode() {
updateViewMode(.list)
}
I can do this, but then the sidebar selection instantly turns gray, which looks odd and other system apps do not behave this way.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
becomeFirstResponder()
}
override var canBecomeFirstResponder: Bool {
return true
}
I'm using multiple scenes in my iPad app.
When I open a new scene from my main window, that new window is always the same size as the previous window.
When I make the main window very small and then create a new scene, that new window is also tiny. When I make the main window very big, you guessed it.
UIWindowScene.sizeRestrictions does not seem to help here. How can I give new windows a default size (it's okay if they're resizable after presenting)? This is such a weird behavior.
Video of the problem in action: https://mastodon.social/@nicoreese/115033539035249909
It appears from my testing that the following is true:
If you close all windows of an app, the app terminates entirely. Minimizing the last window sends it into multitasking. This is different from previous behavior and might have implications on your app's logic.
If you close the last window and quickly tap the app icon again, that same window will come back. Waiting a second before tapping the app icon will bring up the main window (likely because by that point the app was terminated and relaunched).
Is this expected behavior? I did not see any announcement of this.
I find this a bit counterintuitive and would presume that closing the last window would just send the app to multitasking, just like previously. Quitting the app should be reserved by swiping up on it in the multitasking UI or with a new context menu command.
Was it always so tricky to ignore the bottom safe area? Seems like iOS 26 makes this much harder.
I've tried many variations of ignoresSafeArea, safeAreaInset, safeAreaBar, etc. Nothing seems to work. As soon as I add padding, the bottom safe area crashes the party.
This is what I want to achieve:
This is what I get right now:
struct ContentView: View {
var body: some View {
List {
Text("Content")
}
.overlay(alignment: .bottom) {
content
}
}
var content: some View {
VStack {
Text("Custom Container")
}
.frame(maxWidth: .infinity)
.frame(height: 400)
.background(Color.gray, in: .rect(corners: .concentric, isUniform: true))
.padding(15)
}
}