Add a UITableView as a subview crash only on simulator iOS - ios

Is there a problem with adding a UITableView as a subview of aUIView? I had a line of code that was working for months, and recently broke after I updated XCode to 4.6.3. Long story short, I was returning TableViewTwo as a subview of a UIView as a footer of TableViewOne. Please don't ask me why this is necessary, it is just convenient for what I am doing. Well, the app would always crash on the simulator, but not on the device. It would give me a bizarre error and an opaque call stack. The error said unrecognized selector(numberOfSections)sent to instance. Yes, the selector was numberOfSections and not the numberOfSectionsInTableView in the UITableViewDataSource. Well, when I returned the UITableViewTwo as UITableViewOne's footer..everything started working. Does anyone know if there is a problem with adding a UITableView as a subview of a UIView? For more information - see this SO Post(link)

Related

AppleTV app crashes because of a UITableViewCell not providing a parentFocusEnvironment

Since Xcode 14 (AppleTV SDK 16.0) and tvOS 16.0, my AppleTV app crashes when I try to call reloadData() on a UITableView after the user selects a cell (the goal is to update the table model and view). The crash states that a UITableViewCell does not have a parentFocusEnvironment:
*** Assertion failure in -[_UIFocusItemInfo _createFocusedRegion], _UIFocusItemInfo.m:187
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Focus item <UITableViewCell: 0x7f92d202fc00> does not provide a parentFocusEnvironment.'
The app creates regular UITableViewCell hence does not override this property so I don't understand why it is missing.
• On tvOS 15.4 (whatever Xcode version 13.4.1 or 14), the app does not crash and the behaviour is as expected. No system warnings or logs.
• On tvOS 16.0 with XCode 13.4.1 (AppleTV SDK 15.0), the app does not crash either but the unfocused view of the selected UITableViewCell stays in the view hierarchy after the reloading. Also a system log warns that the focus item (UITableViewCell) does not define a parentFocusEnvironment and that the app will crash in a future version -> my crash.
[Assert] Focus item <UITableViewCell: 0x7fe4290a7c00> does not provide a parentFocusEnvironment. This will become an assert in a future version.
[Assert] Failed to create FocusRegion for FocusItem: <UITableViewCell: 0x7ff129856600; frame = (0 800; 880 66); text = 'Show empty sections'; autoresize = W; layer = <CALayer: 0x600003a1f740>> with parentFocusEnvironment: (null) focusItemContainer: (null)
I've been able to create a sample project where the crash can be reproduced: https://github.com/aureliencolas/NavAndTableView
I've filed a feedback request to Apple a week ago with the sample project but I've got no response so far.
Any advice on how to refresh the tableView in a more appropriate way is welcome.
After requesting a code-level support, an Apple engineer helped me find the fix.
Turns out I was not recycling UITableView cells, but creating new ones each time (which I don't usually do but, in this context, there were no point in recycling cells) and doing so, the cell's parentFocusEnvironment was not always defined.
As it was working fine before tvOS 16 and cells recycling not being mandatory, I still consider it a TVOS 16 regression but the issue is now fixed and it's what matters.
Update:
The fix below does only work if the focus has been changed using touch input. Once focus has been changed using the external keyboard arrow keys, it still crashes at (with the same stack trace).
Different approach for now is to store the old parentFocusEnvironment and to return that at all times. This satisfies the assertion within the focus update, but I am still unsure of any side effects this might have:
// Custom Cell
#interface Cell : UITableViewCell
// Weak(!) reference to the last focus environment
#property(nonatomic, weak) id<UIFocusEnvironment> lastParentFocusEnvironment;
#end
#implementation Cell
- (id<UIFocusEnvironment>)parentFocusEnvironment
{
// Always use original parent environment as long as it is available
id environment = [super parentFocusEnvironment];
if (environment)
self.lastParentFocusEnvironment = environment;
return self.lastParentFocusEnvironment;
}
#end
I see the same crash on iPadOS when contents of a focussed table view are cleared. The table view correctly removes the focus and informs the delegate in - (void)tableView:(UITableView *)tableView didUpdateFocusInContext:(UITableViewFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator . However, the view crashes after that delegate method is invoked, stating that the old view, which had focus before, does not have a parentFocusEnvironment, since it had been removed from the view hierarchy.
The crash occurred in the next layout phase after the table view updated, since focus updates appear to happen during layout. This table already uses cell recycling, so that could not be the solution as mentioned in other answers.
The fix was to remove the selection from the table view before calling reloadData like so (assuming selectionFollowsFocus is set on the table view):
// Gather data..
if (!hasRowToFocus) {
// Remove selection
[self.tableView selectRowAtIndexPath:nil animated:NO scrollPosition:UITableViewScrollPositionNone];
// Update focus while the old focussed view is still visible to avoid the crash
[self.tableView setNeedsFocusUpdate];
[self.tableView updateFocusIfNeeded];
}
// Proceed with table view updates..
[tableView reloadData];
...
I'd also consider this a bug, since the SDKs focus validation ignores the fact that an old view might be removed from the view hierarchy and thus lacking a parentFocusEnvironment.

dequeueReusableHeaderFooterViewWithIdentifier not calling init method in ios9

I am using a custom header cell, and while it works correctly in ios8, when I try it on an ios9 device the table calls dequeueReusableHeaderFooterViewWithIdentifier but it doesn't call the initWithFrame (or any init function that I tried) function, and so I just get a blank space for a header file.
Is there a change in how dequeueReusableHeaderFooterViewWithIdentifier works in ios9 that I should be awear of?
Thanks
I had the same problem with a subclass of UITableViewHeaderFooterView. Changing from initWithFrame to initWithReuseIdentifier solved the problem for me.
I could observe the following different behavior under iOS 8 and 9:
Under iOS 8
initWithReuseIdentifier: gets called first then
initWithFrame:
whereas under iOS 9
only
initWithReuseIdentifier:
gets called

Autolayout issue on iOS6: "All dependent constraints should have been removed from the engine and also from the view's list of dependent constraints"

Has anyone encountered this warning message related with autolayout:
All dependent constraints should have been removed from the engine and also from the view's list of dependent constraints
Currently, we have some footerView with several buttons inside and they are hidden or showed depending on the need. We use full autolayout everywhere. Here's the method for hiding/showing this footerView:
- (void)hideFooterView:(BOOL)shouldHide {
self.containerViewBottomConstraint.constant = shouldHide ? 0 : 50; // expand containing view to fit to full screen OR make it smaller to fit with footerView
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded]; // animate expanding screen height to full height
[self.footerView setAlpha:(shouldHide ? 0 : 1)];
} completion:nil];
}
So, when this method is called for the first time then there's no error message. But after the second time mentioned warning appears in console. We can't ignore this warning because in other screens we are encountering crashes with private Apple method calls without any clue how to solve that:
[UILayoutContainerView nsis_shouldIntegralizeVariable:]: message sent to deallocated instance
here's another crash message:
[UILayoutContainerView nsis_valueOfVariable:didChangeInEngine:]: message sent to deallocated instance
I was unable to find anything useful related to "nsis_valueOfVariable:didChangeInEngine:" or "Autolayout dependent constraints" keywords on web. Any ideas?
UPDATE Commenting out line "[self.view layoutIfNeeded]" seems fixed the issue but then there will be no animation...
In my project also this issue came. I was getting same warning "All dependent constraints should have been removed from the engine and also from the view's list of dependent constraints".
As you told, when I ignored it and in other screens I got crashes, showing
[UILayoutContainerView nsis_shouldIntegralizeVariable:]: message sent to deallocated instance
I found that, in my case I was calling [self.view layoutIfNeeded] inside -(void)viewWillDisappear:(BOOL)animated. When I removed this out, the issue was fixed.
No warnings and no crashes.
From this what I understood is, if we call layoutIfNeeded just before the view is being deallocated this warning will come. And in next screens it will cause crashing.
It took so much time to figure out this crash. That's why I am sharing my thoughts.
This may help someone.

UICollectionView's prepareLayout and invalidateLayout

when reading objc.io's 5th issue on UICollectionView + UIKit Dynamics , the 2nd section talked about 'Tiling your Dynamic Behaviors for Performance (related source code)', what confuse me is prepareLayout method is continuously called, but -shouldInvalidateLayoutForBoundsChange: still returns NO, and nowhere called invalidateLayout. shouldn't it just called once ?
I came across a similar issue myself when testing an iOS7 UICollectionViewFlowLayout on an iOS6 device. On an iOS7 device prepareLayout is only called once, but on an iOS6 device it is called when layoutSubviews is trigged by it's parent UIScrollView.
To fix this issue I changed my UICollectionViewFlowLayout class to UICollectionViewLayout. There seems to be a layout issues with UICollectionViewFlowLayout in this case.

SIGABRT between loadView and viewDidLoad

I'm new to iOS development, and having trouble identifying the source of a SIGABRT. I've narrowed it down to something that happens during initialization of a UIViewController subclass, specifically between its loadView and viewDidLoad methods.
I narrowed it down with an NSLog call in each of those method overloads in my UIViewController subclass. However, I'm unable to get any more granularity from the debugger; I can't step into the [super loadView] method. Are there any techniques for debugging a SIGABRT other than NSLogs and stepping through with the debugger? Is there any way to see exactly from where the exception was thrown?
Program-specific details
This program uses Core Data; I created it following this tutorial. I believe the SIGABRT started happening after I ran through the "Relationships In Action" section, and was not happening before (I think I had a successful build at the end of the preceding section). Specifically, I can successfully add a Person, but PersonDetailTableViewController throws a SIGABRT between loadView and viewDidLoad.
I've tried deleting the app from the iPhone simulator, and also running a Product > Clean; neither had any effect.
Found the culprit. I had earlier incorrectly created an IBOutlet by ctrl+dragging from a Table View Cell's Text Field into my UITableViewController subclass. I manually deleted the code this created, but a connection remained in the Connections Inspector. Deleting that connection solved the problem -- no more SIGABRT.
It's unfortunate that Xcode sees the problem (see the exclamation mark in the attached image), but didn't tell me about it in any way except the mysterious SIGABRT....

Resources