TVOS focus stops working in search keyboard

Hi everyone,

I'm trying to solve an issue with focus not being updated in UISearchController keyboard after some letters are typed (one or more if I'm lucky enough to swipe quickly).

This started happening when I switched to Xcode 15 and the latest tvOS SDK.

The focus engine logs do not explain much to me

The result of the focus update was determined from the following preferred focus search:
|
|	Starting preferred focus search.
|	<UIViewController: 0x10711d180>
|	 └ <RCTRootView: 0x10711a810>
|	    │ No more preferred environments. Trying to infer environment from visual layout...
|	    │ Found environment: <UIKeyboard: 0x105ffcc40>
|	    └ <UIKeyboard: 0x105ffcc40>
|	         (info) It's focusable!
|
Moving focus from <UIKeyboard: 0x105ffcc40> to <UIKeyboard: 0x105ffcc40> in focus system <UIFocusSystem: 0x303568600>.

Ignoring focus update request for disappearing focus environment <UIKBFloatingKeyView: 0x105eeb130>.

<<TYPE LETTER GOES HERE >>

 - ISSUE: This environment does not contain the currently focused item.
Ignoring focus update request for disappearing focus environment <_UITextLayoutFragmentView: 0x105fff620>.
 - ISSUE: This environment does not contain the currently focused item.
Ignoring focus update request for disappearing focus environment <UISearchBarTextFieldLabel: 0x105ff6f70>.
 - ISSUE: This environment does not contain the currently focused item.
Ignoring focus update request for disappearing focus environment <UILabel: 0x105ff5090>.
 - ISSUE: This environment does not contain the currently focused item.

In the "focus-freeze" state is not possible to swipe anymore, but I still can repeat typing of the last letter.

I'd appreciate any hints on how to debug this problem. Is it possible to list gesture recognizers or other objects that are consuming TV remote events ?

I've confirmed the the [UIWindow sendEvent:] is still being triggered.

Some additional information:

The search view controller is embedded into a UIView as follows


//UIView initializer

-(instancetype)init {
  if (self = [super initWithFrame: CGRectZero]) {

    //results view placeholder controller which will show search results
    resultsViewController = [[UIViewController alloc] init];

    //seach view controller
    search = [[UISearchController alloc] 
                                  initWithSearchResultsController: resultsViewController];
    search.hidesNavigationBarDuringPresentation = NO;
    search.searchResultsUpdater = nil;

    //temporary disabled - just to minimize number 
    //of dependencies when debugging focus issues
    //search.searchBar.delegate = self;

    search.searchBar.keyboardAppearance = UIKeyboardAppearanceDark;
    containerController = [[UISearchContainerViewController alloc]   
                                                        initWithSearchController:search];

    containerController.view.autoresizesSubviews = YES;
    [self addSubview: containerController.view];

    return self; 
  }
  return nil;
}

//attach UISearchContainerViewController parent UIController
- (UIViewController *)viewControllerForUIView:(UIView*)view
{
  id responder = [self nextResponder];
  while (responder) {
    if ([responder isKindOfClass:[UIViewController class]]) {
      return responder;
    }
    responder = [responder nextResponder];
  }
  return nil;
}

- (void)addControllerToClosestParent:(UIViewController *)controller
{
  if (!controller.parentViewController) {
    UIView *parentView = (UIView *)self.superview;
    while (parentView) {
      UIViewController* vc  = [self viewControllerForUIView: parentView];
      if (vc) {
        [vc addChildViewController:controller];
        [controller didMoveToParentViewController:vc];
        break;
      }
      parentView = (UIView *)parentView.superview;
    }
    return;
  }
}

-(void)didMoveToSuperview {
  if(self.superview) {
    [self addControllerToClosestParent:containerController];
    dispatch_async(dispatch_get_main_queue(), ^{
      [self setNeedsLayout];
      [self layoutIfNeeded];
    });
  }
}

And when swipe stops working the first responder read at [UIWindow: sendEvent] breakpoint is

(lldb) po [(UIWindow*)$arg1 performSelector:@selector(firstResponder)];

<UISearchBarTextField: 0x1078e1a00; frame = (0 0; 1650 70); text = 'i'; opaque = NO; gestureRecognizers = <NSArray: 0x301f6c4b0>; placeholder = To search, start typing, or select one of your previous searches; borderStyle = RoundedRect; background = <_UITextFieldTVBackgroundProvider: 0x3013be5b0: backgroundView=(null), textfield=<NSKVONotifying_UISearchBarTextField: 0x1078e1a00>>; layer = <CALayer: 0x301690fe0>>
TVOS focus stops working in search keyboard
 
 
Q