Skip to content

Conversation

@hbugdoll
Copy link
Contributor

@hbugdoll hbugdoll commented Oct 22, 2025

Fixes #14145.

Introduction:

  • in updateTabBarItem a new UITabBarItem is created and assigned to the ViewController with each property update
  • iOS 18/iPadOS 18 use a modified caching mechanism for the tab bar and the latter one has also introduced a new "floating" tab bar
  • it turned out that
    • under iPadOS 18 it is necessary to use the "original" UITabBarItem to update the badge value
    • but then it becomes a problem, if the icon is set at a later time due to caching mechanism (possibly already a problem under iOS 17)

Description:

  • reuse rootController.tabBarItem when updating the properties, e.g. badge value, of a tab bar item in updateTabBarItem
    • re-init in the case of switching to a system item (with system icon) and vice versa
  • in case of image == nil (lazy loading) an "empty" placeholder image is used now (1x1 px transparent)
    • to prevent the error Inconsistency in UITabBar items and view controllers detected.
  • aligned call sequence for tab bar items with system icons and custom icons
  • added some comments for better clarity

@m1ga
Copy link
Contributor

m1ga commented Oct 23, 2025

Tested it on iPhone and iPad and both badges are set correctly now 👍

@m1ga
Copy link
Contributor

m1ga commented Oct 23, 2025

In another Alloy project I see some issues:

  • I use $.tab_setting.icon = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory,"icon_profil.png").read(); to assign generated icons to the tabs in the open event and I don't see the icons.
  • when I click on a tab it will crash with
[ERROR] Application received error: Inconsistency in UITabBar items and view controllers detected. No view controller matches the UITabBarItem '<UITabBarItem: 0x102f8a7d0> title='Pläne' selected'.
[ERROR]     0   CoreFoundation                      0x00000001804f39e8 __exceptionPreprocess + 172
[ERROR]     1   libobjc.A.dylib                     0x000000018009c084 objc_exception_throw + 72
[ERROR]     2   Foundation                          0x00000001810353c0 _userInfoForFileAndLine + 0
[ERROR]     3   UIKitCore                           0x00000001859c10c0 -[UITabBarController _viewControllerForTabBarItem:] + 388
[ERROR]     4   UIKitCore                           0x00000001859c1164 -[UITabBarController _tabBarDidChangeSelectionToItem:] + 28
[ERROR]     5   UIKitCore                           0x00000001857bdf90 -[UITabBar _didSelectButtonForItem:] + 308
[ERROR]     6   UIKitCore                           0x00000001852e0c78 block_destroy_helper.30 + 43056
[ERROR]     7   UIKitCore                           0x00000001851aea08 __swift_memcpy9_8 + 8720
[ERROR]     8   UIKitCore                           0x00000001861b0fcc -[UIAction performWithSender:target:] + 104
[ERROR]     9   UIKitCore                           0x0000000185ae7e6c -[UIControl _sendActionsForEvents:withEvent:] + 284
[ERROR]     10  UIKitCore                           0x00000001852d87e4 block_destroy_helper.30 + 9116
[ERROR]     11  UIKitCore                           0x00000001852e0924 block_destroy_helper.30 + 42204
[ERROR]     12  UIKitCore                           0x0000000185d408ec -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 76
[ERROR]     13  UIKitCore                           0x0000000185d499ec _UIGestureRecognizerSendTargetActions + 88
[ERROR]     14  UIKitCore                           0x0000000185d46760 _UIGestureRecognizerSendActions + 296
[ERROR]     15  UIKitCore                           0x0000000185d46324 -[UIGestureRecognizer _updateGestureForActiveEvents] + 320
[ERROR]     16  UIKitCore                           0x0000000185d4af30 -[UIGestureRecognizer gestureNode:didUpdatePhase:] + 296
[ERROR]     17  Gestures                            0x000000022efbf64c GFGestureNodeDefaultValue + 4468
[ERROR]     18  Gestures                            0x000000022efdc858 _swift_stdlib_malloc_size + 26304
[ERROR]     19  Gestures                            0x000000022f0070ac __swift_memcpy24_8 + 20672
[ERROR]     20  Gestures                            0x000000022f02e90c GFGestureNodeCoordinatorCreate + 2148
[ERROR]     21  UIKitCore                           0x0000000185d37e18 -[UIGestureEnvironment _updateForEvent:window:] + 468
[ERROR]     22  UIKitCore                           0x000000018629b3d4 -[UIWindow sendEvent:] + 2796
[ERROR]     23  UIKitCore                           0x0000000186279714 -[UIApplication sendEvent:] + 376
[ERROR]     24  Fitness Plan                        0x00000001021f3cd8 -[TiUIApplication sendEvent:] + 404
[ERROR]     25  UIKitCore                           0x000000018630dc6c __dispatchPreprocessedEventFromEventQueue + 1184
[ERROR]     26  UIKitCore                           0x0000000186310920 __processEventQueue + 4800
[ERROR]     27  UIKitCore                           0x0000000186308ecc updateCycleEntry + 168
[ERROR]     28  UIKitCore                           0x0000000185773878 _UIUpdateSequenceRunNext + 120
[ERROR]     29  UIKitCore                           0x000000018617ec90 schedulerStepScheduledMainSectionContinue + 56
[ERROR]     30  UpdateCycle                         0x00000002509462b4 _ZN2UC10DriverCore18continueProcessingEv + 80
[ERROR]     31  CoreFoundation                      0x00000001804114ac __CFMachPortPerform + 164
[ERROR]     32  CoreFoundation                      0x000000018044dbe0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
[ERROR]     33  CoreFoundation                      0x000000018044d1f8 __CFRunLoopDoSource1 + 480
[ERROR]     34  CoreFoundation                      0x000000018044c2c0 __CFRunLoopRun + 2100
[ERROR]     35  CoreFoundation                      0x0000000180446e24 _CFRunLoopRunSpecificWithOptions + 496
[ERROR]     36  GraphicsServices                    0x00000001925319bc GSEventRunModal + 116
[ERROR]     37  UIKitCore                           0x000000018625fc3c -[UIApplication _run] + 772
[ERROR]     38  UIKitCore                           0x0000000186263e64 UIApplicationMain + 124
[ERROR]     39  Fitness Plan                        0x00000001021845b0 main + 884
[ERROR]     40  dyld                                0x00000001029293d0 start_sim + 20
[ERROR]     41  ???                                 0x0000000102a64d54 0x0 + 4339420500
[ERROR] libc++abi: terminating due to uncaught exception of type NSException

13.0.0:

13.1.0:

@m1ga m1ga self-requested a review October 23, 2025 16:56
@hbugdoll
Copy link
Contributor Author

@m1ga Thanks for testing and reporting 👍
I can now reproduce the issue and I'am working on it.

@hbugdoll hbugdoll mentioned this pull request Oct 25, 2025
1 task
@hbugdoll
Copy link
Contributor Author

hbugdoll commented Oct 27, 2025

@m1ga The new issue could be reproduced by modifying your example from #14145 (comment) as follows

var win1 = Ti.UI.createWindow({
    backgroundColor: 'blue',
    title: 'Blue'
});
win1.add(Ti.UI.createLabel({text: 'I am a blue window.'}));

var win2 = Ti.UI.createWindow({
    backgroundColor: 'red',
    title: 'Red'
});
win2.add(Ti.UI.createLabel({text: 'I am a red window.'}));

var tab1 = Ti.UI.createTab({
    window: win1,
    title: 'Blue',
    badge: 10
}),
tab2 = Ti.UI.createTab({
    window: win2,
    title: 'Red'
}),
tabGroup = Ti.UI.createTabGroup({
    tabs: [tab1, tab2]
});
tabGroup.open();

setTimeout(function(){
    tab1.icon = '/assets/images/tab1.png';
    tab2.icon = '/assets/images/tab2.png';
    tab2.badge=2;
}, 2000);

which initially leads to [[UITabBarItem alloc] initWithTitle:title image:nil selectedImage:nil] in updateTabBarItem. Actually, and so far, no problem – the tab bar items are created without icons and the icons will be set later.

But iOS 18 has a modified caching mechanism for the tab bar, which leads to these strange problems...
It appears that tab bar items with icons are handled differently than icon-less tab bar items.
Adding an icon at a later time, apparently a new tab bar item is created internally and then no longer doesn't match its view controller.

Using an "empty" placeholder image at creation time has solved this problem.

@m1ga
Copy link
Contributor

m1ga commented Oct 28, 2025

It's not crashing anymore but please check the "Red" (2nd tab) title in your example: it's at the wrong position at first and then jumps into place when the timeout is running

In my app it looks like this when I start the app:

and after I clicked on all items it's correct:

@hbugdoll hbugdoll changed the title fix(ios): fixed TabBarItem's badge update for iPadOS 18+ fix(ios): fixed TabBarItem's badge update for iOS 18+ Oct 28, 2025
@hbugdoll hbugdoll marked this pull request as draft October 30, 2025 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iOS 18 set tab's badge

2 participants