I have a tableview where each cell contains a textview.
Steps to reproduce the crash.
Write something in the textview of first row (keyboard is open)
Scroll the tableview downwards where the first row is not visible anymore . however, the keyboard is still open
I choose another tab where in code I remove the view which contains the tableview from its superview then the app crashes
Here is the stack trace
at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.void_objc_msgSendSuper (intptr,intptr) <IL 0x00024, 0xffffffff>
at MonoTouch.UIKit.UIView.RemoveFromSuperview () [0x00031] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIView.g.cs:848`
i tried to perform a ResignFirstResponder with the same results.
Moreover, if the keyboard is not opened there is no crash
It is only reproduced on IOS 7
The problem is that the UITableViewCells i am creating in my UITableViewSource are being freed by the managed garbage collector, because they're not referenced from managed code when that method exits.
There are two ways to solve this problem:
Keep a list of cells you've created in a class variable in the UITableViewSource class. The problem with this approach is that you have extra bookkeeping to do in order to remove cells from the list when they're no longer used.
Create a custom subclass of UITableViewCell. Custom subclasses are treated differently at runtime in Xamarin.iOS, and we make sure they're not freed until their corresponding native object is freed:
class CustomCell : UITableViewCell
{
public CustomCell(UITableViewCellStyle Style, string Identifier) : base(Style, Identifier) { }
}
Related
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.
I have just started with iOS development in objective C and I'm finding it difficult to get my head around UIView objects.
Here is what I'm doing:
In an existing project, I'm adding a new UIViewController.
In a storyboard I'm dragging and dropping UI elements.
I added some constraints into each of the UI elements (just playing around, there is no specific constraint as such, this could be anything).
Dragging each of these UIElement to ViewController.h to create a handler.
In ViewController.m file I'm trying to first synthesize all those objects and then further play around with some logics (again nothing very specific).
In ViewDidLoad I'm try to perform loading my UI elements.
During runtime when I trigger my custom UIViewController, then I could see from debugger that it actually comes into controller's ViewDidLoad section.
Problem:
During runtime, all the UI elements have nil assign to them. I don't understand this that why is synthesize not allocating them any memory. The execution just goes over my logics, but does nothing. I don't see anything displayed in my screen.
Question:
Why is this so? Why even after setting my UI constraints in storyboard and synthesizing each UI handler objects, I was not able to allocate memory to my UI objects?
I get a crash when quickly scrolling through a UITableView.
The crash is :
*** -[Not A Type release]: message sent to deallocated instance 0x1aded1c0
And the exception breakpoint indicates this as the source:
- (void)updateInfo:(Item*)item{
if (!item) {
return;
}
Program *prg = (Program *)item;
self.titleLabel.text = prg.title; // crash here
self.descriptionLabel.text = prg.item_description;
}
This method is inside the custom table view cell subclass and it is called when data from the internet is ready to be displayed in the cell.
I have never seen this kind of crash before...
What is the best way to fix it?
Reason:
As you scroll the tableview, the cells on top get released and when data comes from internet for those cell, they have already been released. So, change your logic. You generally receive this error when you try to access and update an object which has already been released. As you are saying that this method is inside your custom cell, so it clearly indicates that the cell is already released. That's why your app gets crashed when you try to update any view of that cell.
Solution:
Either you can reload your whole tableview or reload those specific cells when you receive data.
Where are you calling the method "updateInfo"? You should call this in cellForRowAtIndexPath. You should not store a reference to a cell and then call this.
When you get the data from your service you just call self.tableView reloadData (or perhaps reloadRowsAtIndexPaths if you know which row needs update and dont want a performance hit)
I have a fairly basic MainWindow.xib with a source list-style sidebar. I created it by dragging the Source List template into the window, which already contains two NSTableCellViews: HeaderCell and DataCell.
The latter consists of an icon (using NSImageView) and a label (NSTextField). Instead, I want the label and another, smaller label underneath. In IB, this looks as follows:
If I focus on just DataCell, it highlights accordingly:
Thing is, actually running the program, it looks nothing like the template:
Notice how the two NSTextFields just get smashed together into one. My understanding was that view-based NSOutlineViews (and view-based NSTableViews, for that matter) are supposed to be designed as a template from within IB. Instead, the dimensions from the template seem to get mostly ignored.
Here's the code that sets the view's values from the data source:
public class TourSourceListDelegate : NSOutlineViewDelegate
{
public override bool IsGroupItem(NSOutlineView outlineView, MonoMac.Foundation.NSObject item)
{
return (item as TourSourceListDataSource.Item).IsHeader;
}
public override NSView GetView(NSOutlineView outlineView, NSTableColumn tableColumn, MonoMac.Foundation.NSObject item)
{
if (IsGroupItem(outlineView, item))
{
return outlineView.MakeView("HeaderCell", this);
}
else
{
var data = item as TourSourceListDataSource.Item;
var dataView = outlineView.MakeView("DataCell", this);
(dataView.Subviews[0] as NSTextField).StringValue = data.Name;
(dataView.Subviews[1] as NSTextField).StringValue = data.Date_start.ToShortDateString();
return dataView;
}
}
}
I've tried overriding GetRowHeight, but that doesn't seem to resolve the problem (it makes more room, but still doesn't let the views distribute themselves properly), nor does it seem necessary.
I've also tried playing with the various Autosizing, Autoresizes Subviews, etc. toggles in IB, but that doesn't seem to produce intuitive results, and again, it doesn't seem necessary — the view as presented in IB is exactly what I want, just with slightly longer labels in practice.
I haven't tried converting this to AutoLayout yet.
What obvious step am I missing?
Some more info that probably doesn't make a difference: this is a Xamarin.Mac/MonoMac project with Xcode 5.0, MacOSX10.8.sdk, Xamarin Studio 4.0.12, Xamarin.Mac 4.0.12, and Mono 3.2.3 (targeting Mono / .NET 4.0). I've also enabled App Sandboxing.
What's important in interface builder is the view hierarchy. What kind of view is that cell? Are those labels really subviews of the cellview or not? The hierarchy should look something like:
One thing that's fishy that I see is accessing dataView.Subviews[0] and [1]. If you're adding subviews to your cells then should be creating your own NSTableViewCell subclasses, with each view connecting to the subclass' IBOutlet properties. The subclass doesn't need any code in its implementation, just the declaration of its properties in #interface, such as titleField and descriptionField, and an empty #implementation that auto-synthesizes them.
Then makeViewWithIdentifier (or apprently the glue MakeView in Xamarin) when passed the right identifier should create your NSTableViewCell subclass, and at runtime you can verify that using po dataView in the debugger. Then you access the subviews using the properties of your NSTableViewCell subclass' interface instead of assuming which view is in which position with the subview array, using dataView.titleField and dataView.descriptionField.
If your cell view has one text field then you can use NSTableViewCell without subclassing, but do connect up the textField outlet (its connected by default as long as you don't delete & recreate the cell view's label view) so you can access it through the property, again instead of having to dive into the subviews array.
All that said, it's not really clear why you're seeing what you are. It looks like those aren't the subviews you expect, and might even look like the wrong fonts as well as in the wrong positions. Using a custom subclass of NSTableViewCell and verifying its class at runtime is a good way of making sure it's creating the view you expect, but you can also dump the subview within the debugger using po [dataView _subtreeDescription].
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)