DequeueReusableCell crashes app on iPhone 4S only - c#

I'm developing an app using Xamarin + Mvvmcross. Currently it's working fine on iPad Mini, iPad 2,3, iPhone 5S and 6. Strangely one of the views is crashing on iPhone 4S running iOS 7.1. All tests were done using real devices.
Here's the crash:
https://gist.github.com/nunohorta/2b84245899e8c0daa116
The code for the table source is this one:
public class MessagesTableSource : MvxStandardTableViewSource
{
UITableView _tableview;
MessagesView _parent;
UILabel messageLabel;
private static readonly NSString MessageCellIdentifier = new NSString("MessageCell");
public MessagesTableSource(UITableView tableView, MessagesView parent) : base(tableView)
{
_tableview = tableView;
_parent = parent;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return _parent.ViewModel.Messages != null ? _parent.ViewModel.Messages.Count : 0;
}
public override nint NumberOfSections (UITableView tableView)
{
if (_parent.ViewModel.Messages != null && _parent.ViewModel.Messages.Count > 0) {
return 1;
} else {
/*
* Custom View here
*
* */
return 0;
}
}
protected override UITableViewCell GetOrCreateCellFor (UITableView tableView, NSIndexPath indexPath, object item)
{
var cell = (MessageCell)tableView.DequeueReusableCell("MessageCell");
return cell;
}
}
I'm also registering the custom class like this on the viewDidLoad:
tableView.RegisterNibForCellReuse(UINib.FromName("MessageCell", NSBundle.MainBundle), MessageCellIdentifier);
I have no idea why is it crashing just for one device...The crash seems to happen on the UIKit/CoreFoundation.

You may need to register MessageCell Nib to custom MessageCell Class, like in view did load method. Because for very first time it may couldn't found cell with identifier.
tableView.registerNib(UINib(nibName: "CustomOneCell", bundle: nil), forCellReuseIdentifier: "CustomCellOne")
To deque cell with identifier
tableView.dequeueReusableCellWithIdentifier("CustomCellOne", forIndexPath: indexPath) as! CustomOneCell
I hope it may help to resolve issue.

Related

Selector in UITableViewCell in Xamarin

I need the UIMenuItem to call a method inside the UITableViewCell. Something similar is possible in swift as explained here: https://stackoverflow.com/a/31358474/202179 .
At the moment I am only able to call the method inside the UIViewController from the UIMenuItem if I add an Export attribute to the method.
There is some trick in the export of this method in the cell, but I have failed to find it till now. I would expect this code to work, but it doesn't:
[Register("CustomCell")]
public class CustomCell : UITableViewCell
{
public CustomCell(IntPtr intPtr) : base(intPtr)
{
var menuItem = new UIMenuItem("Menu Item", new ObjCRuntime.Selector("CustomCell.SeekSelectedText"));
UIMenuController.SharedMenuController.MenuItems = new UIMenuItem[] { menuItem };
UIMenuController.SharedMenuController.Update();
}
[Export("SeekSelectedText")]
void SeekSelectedText()
{
//do something
}
}
As said just quoting a different selector inside the UIViewController works, so the problem is that this selector doesn't appear to be recognized whatever I try.
Here is my test and the custom UIMenuItem works fine.
First, define a custom cell class which inherits UITableViewCell
class MyCell: UITableViewCell
{
public MyCell(UITableViewCellStyle style, string reuseIdentifier):base(style, reuseIdentifier)
{
}
[Export("custom")]
void Custom()
{
//do something
Console.WriteLine("custom pop up");
}
public override bool CanPerform(Selector action, NSObject withSender)
{
if (action == new Selector("custom"))
return true;
else
return false;
}
}
Second, set the source of your UITableView
class MyTableViewSource : UITableViewSource
{
int i = 0;
// create custom cell
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
string cellStr = "cell";
MyCell cell = (MyCell)tableView.DequeueReusableCell(cellStr);
if (cell == null)
{
cell = new MyCell(UITableViewCellStyle.Subtitle, cellStr);
cell.TextLabel.Text = $"User Name {i}";
cell.DetailTextLabel.Text = $"details here... {i++}";
}
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return 10;
}
}
Then override the realted methods(e.g., ShouldShowMenu, CanPerformAction).
class MyTableViewDelegate : UITableViewDelegate
{
public override bool ShouldShowMenu(UITableView tableView, NSIndexPath rowAtindexPath)
{
return true;
}
public override bool CanPerformAction(UITableView tableView, Selector action, NSIndexPath indexPath, NSObject sender)
{
return true;
}
public override void PerformAction(UITableView tableView, Selector action, NSIndexPath indexPath, NSObject sender)
{
}
public override bool ShouldHighlightRow(UITableView tableView, NSIndexPath rowIndexPath)
{
return true;
}
}
Last, don't foget to add custom MenuItem to your UITableViewCell.
UIMenuController.SharedMenuController.MenuItems = new UIMenuItem[] {
new UIMenuItem ("Custom", new Selector ("custom"))
};
Since UICollectionView has similar functions to UITableVIew, you can directly refer to the sample SimpleCollectionView.

UITableViewCell not being rendered correctly

We've created a TableViewController so that a user can enable/disable different notification types. After the initial load, everything is fine until the user scrolls to the bottom then back to the top and the first 1-2 table view cells aren't displaying correctly.
Example:
https://imgur.com/7n2VpTo
Typically deleting and recreating the view controller and xib/cs files fixes this, but was wondering if any one knows the cause of this.
Controller Code:
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 305;
}
public override nint NumberOfSections(UITableView tableView)
{
return 1;
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return _numRows;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(Setting.Key) as Setting;
if (cell == null)
{
var values = _settings.Where(s => s.Index == indexPath.Row).FirstOrDefault();
cell = new Setting(values);
var views = NSBundle.MainBundle.LoadNib(Setting.Key, cell, null);
cell = Runtime.GetNSObject(views.ValueAt(0)) as Setting;
}
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
cell?.PopulateData(_settings.Where(s => s.Index == indexPath.Row).FirstOrDefault(), this);
return cell;
}
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
}
Cell Code:
public partial class Setting : UITableViewCell
{
public static readonly NSString Key = new NSString("Setting");
public static readonly UINib Nib;
public SettingModel Values { get; set; }
static Setting()
{ 
Nib = UINib.FromName("Setting", NSBundle.MainBundle);
} 
 
protected Setting(IntPtr handle) : base(handle) { }

public Setting() : base() {

 }

public override void LayoutSubviews()
{ 
base.LayoutSubviews();
}

public void PopulateData(SettingModel values) 
{
//logic...
}
}
Upgrading to Visual Studio for Mac 8.6.5 resolved the issue.

UITableviewCell GetCell is not being called

I am using Visual Studio Community 2017 for Mac. I have a UITableview named SchoolSchedule. I am setting the Source from a button, but then when I click the button GetCell is not called, however, RowsInSection is called.
Here is my class:
public class ScheduleTableViewSource : UITableViewSource
{
private Schedule[] school;
public ScheduleTableViewSource(Schedule[] school)
{
this.school = school;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = (ScheduleCell) tableView.DequeueReusableCell("cell_id", indexPath);
var school1 = school[indexPath.Row];
cell.Updatecell(school1);
cell.TextLabel.Text = school[indexPath.Row].Site;
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return school.Length;
}
}
here is my button code :
partial void Get_button_TouchUpInside(UIButton sender)
{
bool check = NetworkInterface.GetIsNetworkAvailable();
if(check)
{
Service1 client = new Service1();
var school = client.CypressRidge("CypressRidge");
SchoolSchedule.Source = new ScheduleTableViewSource(school);
SchoolSchedule.ReloadData();
}
else{
Console.Write("Error no Internet connection");
return;
}
// int stop =0;
}
I have checked and there is data coming in from my service. so that is not the problem. can anyone help?
I had to deleted the table and make a new one.
there a bug in Xamarin.
I had the same problem and I managed to fix it setting up Identifier property of TableView first prototype row - in storyboard
In addition to implementing the IUITableViewDelegate and IUITableViewDataSource interfaces in the .cs file, calling RegisterNibForCellReuse, and assigning the table view's EstimatedRowHeight, it's easy to forget to set the data source and delegate properties of the table view in the XIB.

Exception while launching my iOS Xamarin App

I'm faced with a problem with my iOS Xamarin App.
Whenever I try to add a tableView in one of my views with the Storyboard, and I launch my app I have always the same error.
Foundation.MonoTouchException: Objective-C exception thrown. Name:
NSInvalidArgumentException Reason: -[TableSource initWithCoder:]:
unrecognized selector sent to instance 0x17d6a620
Here is my TableSource code:
using Foundation;
using System;
using UIKit;
namespace SmartTransportNatif.iOS2
{
public partial class TableSource : UITableViewSource
{
protected string[] tableItems;
protected string cellIdentifier = "TableCell";
HomeTableController home;
public TableSource (IntPtr handle) : base (handle)
{
}
public TableSource (string[] items, HomeTableController home)
{
this.home = home;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return tableItems.Length;
}
/// <summary>
/// Called when a row is touched
/// </summary>
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
UIAlertController okAlertController = UIAlertController.Create("Row Selected", tableItems[indexPath.Row], UIAlertControllerStyle.Alert);
okAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
home.PresentViewController(okAlertController, true, null);
tableView.DeselectRow(indexPath, true);
}
/// <summary>
/// Called by the TableView to get the actual UITableViewCell to render for the particular row
/// </summary>
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
// request a recycled cell to save memory
UITableViewCell cell = tableView.DequeueReusableCell(cellIdentifier);
// if there are no cells to reuse, create a new one
if (cell == null)
cell = new UITableViewCell(UITableViewCellStyle.Default, cellIdentifier);
cell.TextLabel.Text = tableItems[indexPath.Row];
return cell;
}
}
}
Here is my storyboard:
Here are the properties of my Tableview in the HomeTableController:
Does someone know what is missing or wrong?

Xamarin Forms - How to create custom render to give TableSection the default iOS Footer?

I want to add the default iOS footer to the tablesection in the tableview in Xamarin Forms. How can I go about doing this? I assume a customer renderer but I'm only reading that this can be done for Tableview?
To show an example, the following image is from Xcode storyboards when I enter the footer text on a static cell.
A Custom renderer is right, but you will have to use a custom renderer for the entire TableView. From there, you will need to override the TableViewModelRenderer and then the GetViewForFooter method in that ModelRenderer. Here's something that might help get you started:
public class FooterTableViewRenderer : TableViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
var tableView = Control as UITableView;
var formsTableView = Element as TableView;
tableView.WeakDelegate = new CustomFooterTableViewModelRenderer (formsTableView);
}
private class CustomFooterTableViewModelRenderer : TableViewModelRenderer
{
public CustomFooterTableViewModelRenderer(TableView model) : base(model)
{
}
public override UIView GetViewForFooter(UITableView tableView, nint section)
{
return new UILabel()
{
Text = TitleForFooter(tableView, section), // or use some other text here
TextAlignment = UITextAlignment.Center
};
}
}
}
As mentioned in my comments below, you can alternatively override other methods in your TableViewModelRenderer:
public override nfloat GetHeightForFooter(UITableView tableView, nint section)
{
return 10;
}
public override string TitleForFooter(UITableView tableView, nint section)
{
return "This is the title for this given section";
}

Categories

Resources