UIDeferredMenuElement With Uncached Provider Not Working on Mac Catalyst. Uncached provider block never called and menu displays as "Loading"

I'm trying to create a dynamic menu on Mac Catalyst. Using a UIBarButtonitem like so to make a "pull down" button:

    UIDeferredMenuElement *deferredmenuElement;
    deferredmenuElement = [UIDeferredMenuElement elementWithUncachedProvider:^(void (^ _Nonnull completion)(NSArray<UIMenuElement *> * _Nonnull))
    {
        UIAction *actionOne = [UIAction actionWithTitle:@"Action One" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
            NSLog(@"action one fired.");
        }];
        
        UIAction *actionTwo = [UIAction actionWithTitle:@"Action Two" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
            NSLog(@"action two fired.");
        }];
        
        UIAction *actionThree = [UIAction actionWithTitle:@"Action Three" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
            NSLog(@"action three fired.");
        }];
        
        completion(@[actionOne,actionTwo,actionThree]);
    }];
    
    UIMenu *wrappedMenu = [UIMenu menuWithChildren:@[deferredmenuElement]];
    
    UIBarButtonItem *uiBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:nil
                                                                        menu:wrappedMenu];
    
    uiBarButtonItem.image = [UIImage systemImageNamed:@"rectangle.and.pencil.and.ellipsis"];
    self.navigationItem.rightBarButtonItems = @[uiBarButtonItem];

The button appears in the toolbar but when I click it to expose the menu I get a menu with on element in it that says "Loading...". The the uncached provider block is never called.

Running Ventura 13.2.1 and Xcode 14.2.

I filed FB12062113

Haven't seen this on Ventura. On Monterey the whole deferred thing didn't work at all but have used it on most every Ventura version without issue. Though I guess I don't have any menus attached to button bar items. I wonder if not implemented there.

Still not fixed in Ventura 13.3. Can you show your code so I can see what's different from mine? I tried using it with a UIButton instead of UIBarButtonItem and then adding it to my NSToolbar with NSUIViewToolbarItem but still not working. The menu just shows a "Loading..." item and the uncached provider block is never called.

Still broken on Ventura 13.5.2.

Also it doesn't work when creating a pull down UIButton. The following button just show "Loading..." and the provider block is never called:

  UIDeferredMenuElement *deferredmenuElement;
    deferredmenuElement = [UIDeferredMenuElement elementWithUncachedProvider:^(void (^ _Nonnull completion)(NSArray<UIMenuElement *> * _Nonnull))
    {
        UIAction *actionOne = [UIAction actionWithTitle:@"Action One" 
                                                  image:nil
                                             identifier:@"fake.action.test"
                                                handler:^(__kindof UIAction * _Nonnull action) {
            NSLog(@"action one fired.");
        }];
        
        
        completion(@[actionOne]);
    }];
    
    UIMenu *someMenu = [UIMenu menuWithChildren:@[deferredmenuElement]];
    UIButton *pullDownButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [pullDownButton setTitle:@"Pull Down Button" forState:UIControlStateNormal];
    [pullDownButton sizeToFit];
    self.button = pullDownButton;
    self.button.menu = someMenu;
    self.button.showsMenuAsPrimaryAction = YES;
    [self.view addSubview:pullDownButton];
    //Position the button...

On Mac Catalyst I did get the UIDeferredMenuElement elementWithUncachedProvider: block to be called only when creating a menu for a UIContextMenuConfiguration directly but if you're actually loading data async to build the menu you can't use dispatch_async_get_main_queue to call the completion block on the main thread.

 UIDeferredMenuElement *deferredMenuElement = [UIDeferredMenuElement elementWithUncachedProvider:^(void (^ _Nonnull completion)(NSArray<UIMenuElement *> * _Nonnull)) {
     //Load whatever async. 
       dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
        dispatch_async(queue, ^{

              //You can't do this. The menu will never update because of the run loop mode.
              dispatch_async(dispatch_get_main_queue(), ^{ 
                      //Build UIMenu with data loaded and call the completion block on the main queue.
                      UIMenu *menu = //...make it
                      completion(@[menu])
                   });
    
               //Instead you have to pass the block to a method like this, then invoke the block.
               [self performSelectorOnMainThread:@selector(builtMenuBlock:)
                                   withObject:completion
                                waitUntilDone:NO
                                        modes:@[NSRunLoopCommonModes]];
}];


Still broken on macOS Sonoma.

Still broken in 14.4.1. Quality software by Apple. Top notch.

I ran into this issue recently and found a workaround to this. Don't attach the menu to the bar button item. Instead use a UIButton as the custom view (sorry about the bastardized ObjC code):

let optionsButton = [UIButton buttonWithType:UIButtonTypeCustom];
[optionsButton setImage:optionsImage forState:UIControlStateNormal];
optionsButton.showsMenuAsPrimaryAction = YES;
optionsButton.menu = menu;
optionsBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:optionsButton];

I want to saw if I changed the button type to .system then I got the same 'Loading...' menu item forever. But when it is custom seems to work. Of course now the bar button item behaves a little differently when the window isn't active so you'll have to write code to tint it to look inactive as needed. But hey the menu works.

UIDeferredMenuElement With Uncached Provider Not Working on Mac Catalyst. Uncached provider block never called and menu displays as "Loading"
 
 
Q