Skip to content

Commit

Permalink
Better null handling
Browse files Browse the repository at this point in the history
In CvCell in my app I was getting some weird null exceptions that while they do not make a lot of sense to get to the GetCell call, I can do a bit better job of mitigating those exceptions to originate from this library.
  • Loading branch information
Redth committed Apr 18, 2024
1 parent 0fa6337 commit ca708e9
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 145 deletions.
2 changes: 2 additions & 0 deletions VirtualListView/Apple/CvCell.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace Microsoft.Maui;

internal class CvCell : UICollectionViewCell
{
internal const string ReuseIdUnknown = "UNKNOWN";

public VirtualListViewHandler Handler { get; set; }

public WeakReference<NSIndexPath> IndexPath { get; set; }
Expand Down
77 changes: 49 additions & 28 deletions VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Foundation;
#nullable enable
using Foundation;
using UIKit;

namespace Microsoft.Maui;
Expand All @@ -20,54 +21,74 @@ public CvDataSource(VirtualListViewHandler handler)

public override nint NumberOfSections(UICollectionView collectionView)
=> 1;

public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var info = Handler?.PositionalViewSelector?.GetInfo(indexPath.Item.ToInt32());

var data = Handler?.PositionalViewSelector?.Adapter?.DataFor(info.Kind, info.SectionIndex, info.ItemIndex);

var reuseId = Handler?.PositionalViewSelector?.ViewSelector?.GetReuseId(info, data);
object? data = null;

var nativeReuseId = info.Kind switch
var nativeReuseId = CvCell.ReuseIdUnknown;

if (info is not null)
{
PositionKind.Item => itemIdManager.GetReuseId(collectionView, reuseId),
PositionKind.SectionHeader => sectionHeaderIdManager.GetReuseId(collectionView, reuseId),
PositionKind.SectionFooter => sectionFooterIdManager.GetReuseId(collectionView, reuseId),
PositionKind.Header => globalIdManager.GetReuseId(collectionView, reuseId),
PositionKind.Footer => globalIdManager.GetReuseId(collectionView, reuseId),
_ => "UNKNOWN",
};

var cell = (collectionView.DequeueReusableCell(nativeReuseId, indexPath) as CvCell)!;
data = Handler?.PositionalViewSelector?.Adapter?.DataFor(info.Kind, info.SectionIndex, info.ItemIndex);

if (data is not null)
{
var reuseId = Handler?.PositionalViewSelector?.ViewSelector?.GetReuseId(info, data);

nativeReuseId = info.Kind switch
{
PositionKind.Item => itemIdManager.GetReuseId(collectionView, reuseId),
PositionKind.SectionHeader => sectionHeaderIdManager.GetReuseId(collectionView, reuseId),
PositionKind.SectionFooter => sectionFooterIdManager.GetReuseId(collectionView, reuseId),
PositionKind.Header => globalIdManager.GetReuseId(collectionView, reuseId),
PositionKind.Footer => globalIdManager.GetReuseId(collectionView, reuseId),
_ => CvCell.ReuseIdUnknown,
};
}
}

var nativeCell = collectionView.DequeueReusableCell(nativeReuseId, indexPath);
if (nativeCell is not CvCell cell)
return (UICollectionViewCell)nativeCell;

cell.SetTapHandlerCallback(TapCellHandler);
cell.Handler = Handler;
cell.IndexPath = new WeakReference<NSIndexPath>(indexPath);

cell.ReuseCallback = new WeakReference<Action<IView>>((rv) =>
{
if (cell?.VirtualView?.TryGetTarget(out var cellVirtualView) ?? false)
Handler.VirtualView.ViewSelector.ViewDetached(info, cellVirtualView);
if (info is not null && (cell.VirtualView?.TryGetTarget(out var cellView) ?? false))
Handler?.VirtualView?.ViewSelector?.ViewDetached(info, cellView);
});

if (info.SectionIndex < 0 || info.ItemIndex < 0)
info.IsSelected = false;
else
info.IsSelected = Handler?.IsItemSelected(info.SectionIndex, info.ItemIndex) ?? false;
if (info is not null)
{
if (info.SectionIndex < 0 || info.ItemIndex < 0)
info.IsSelected = false;
else
info.IsSelected = Handler?.IsItemSelected(info.SectionIndex, info.ItemIndex) ?? false;
}

if (cell.NeedsView)
if (cell.NeedsView && info is not null && data is not null)
{
var view = Handler?.PositionalViewSelector?.ViewSelector?.CreateView(info, data);
cell.SetupView(view);
if (view is not null)
cell.SetupView(view);
}

cell.UpdatePosition(info);

if (cell.VirtualView.TryGetTarget(out var cellVirtualView))
if (info is not null)
{
Handler?.PositionalViewSelector?.ViewSelector?.RecycleView(info, data, cellVirtualView);
cell.UpdatePosition(info);

if (data is not null && (cell.VirtualView?.TryGetTarget(out var cellVirtualView) ?? false))
{
Handler?.PositionalViewSelector?.ViewSelector?.RecycleView(info, data, cellVirtualView);

Handler.VirtualView.ViewSelector.ViewAttached(info, cellVirtualView);
Handler?.VirtualView?.ViewSelector?.ViewAttached(info, cellVirtualView);
}
}

return cell;
Expand Down
23 changes: 13 additions & 10 deletions VirtualListView/Apple/CvDelegate.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public CvDelegate(VirtualListViewHandler handler, UICollectionView collectionVie
{
Handler = handler;
NativeCollectionView = new WeakReference<UICollectionView>(collectionView);
collectionView.RegisterClassForCell(typeof(CvCell), CvCell.ReuseIdUnknown);
}

internal readonly WeakReference<UICollectionView> NativeCollectionView;
Expand All @@ -27,20 +28,22 @@ public override void ItemDeselected(UICollectionView collectionView, NSIndexPath
void HandleSelection(UICollectionView collectionView, NSIndexPath indexPath, bool selected)
{
//UIView.AnimationsEnabled = false;
var selectedCell = collectionView.CellForItem(indexPath) as CvCell;

if ((selectedCell?.PositionInfo?.Kind ?? PositionKind.Header) == PositionKind.Item)
if (collectionView.CellForItem(indexPath) is CvCell selectedCell
&& (selectedCell.PositionInfo?.Kind ?? PositionKind.Header) == PositionKind.Item)
{
selectedCell.UpdateSelected(selected);

var itemPos = new ItemPosition(
selectedCell.PositionInfo.SectionIndex,
selectedCell.PositionInfo.ItemIndex);
if (selectedCell.PositionInfo is not null)
{
var itemPos = new ItemPosition(
selectedCell.PositionInfo.SectionIndex,
selectedCell.PositionInfo.ItemIndex);

if (selected)
Handler?.VirtualView?.SelectItem(itemPos);
else
Handler?.VirtualView?.DeselectItem(itemPos);
if (selected)
Handler?.VirtualView?.SelectItem(itemPos);
else
Handler?.VirtualView?.DeselectItem(itemPos);
}
}
}

Expand Down
Loading

0 comments on commit ca708e9

Please sign in to comment.