You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin iOS F#设置UICollectionViewDelegateFlowLayout引发空引用异常

问题分析与解决方案

你遇到的崩溃问题根源在于错误地将控制器的handle传递给了CollectionViewFlowDelegate的构造函数,以及后续的Delegate实例生命周期管理问题,具体原因和解决办法如下:

为什么设置代理后会崩溃?

在Xamarin iOS中,带IntPtr handle的构造函数是用来绑定已经由Objective-C Runtime创建的对象(比如从故事板/XIB加载的实例)。你把LandlordHome控制器的handle传给CollectionViewFlowDelegate的构造函数,相当于让这个Delegate实例绑定到控制器的Objective-C对象上,这会导致Runtime混淆两个对象的身份,进而引发内存管理异常,最终导致你的listings变量在后续调用中被意外置为null,触发NullReferenceException。

另外,就算构造函数没问题,如果你只是临时创建Delegate实例并赋值给CollectionView.Delegate,而没有保留强引用,.NET的GC可能会回收这个实例(因为UICollectionView对Delegate的引用是弱引用),同样会引发各种异常。

解决办法

这里提供两种可靠的解决方案,你可以根据需求选择:

方案1:修复Delegate的构造与生命周期管理

首先修改CollectionViewFlowDelegate的定义,添加无参数构造函数(手动创建实例时不需要依赖IntPtr handle):

type CollectionViewFlowDelegate () = 
    inherit UICollectionViewDelegateFlowLayout ()
    override x.GetSizeForItem(collectionView : UICollectionView, layout : UICollectionViewLayout, indexPath : NSIndexPath) = CGSize(100.0, 300.0)

然后在控制器中保留对Delegate实例的强引用,避免被GC回收:

[<Register ("LandlordHome")>]
type LandlordHome (handle:IntPtr) = 
    inherit UICollectionViewController (handle)
    let addToList (listan:List<Listing>) (element:Listing) = element::listan
    let mutable listings : List<Listing> = List.Empty
    // 强引用保存Delegate实例,防止被GC回收
    let flowDelegate = CollectionViewFlowDelegate()
    
    override x.ViewDidLoad () = 
        base.ViewDidLoad ()
        x.View.BackgroundColor <- UIColor.Gray
        for i in 1..10 do 
            let listing : Listing = new Listing(....code....)
            listings <- listing::listings
        x.CollectionView.BackgroundColor <- UIColor.Green
        // 使用保留的Delegate实例赋值
        x.CollectionView.Delegate <- flowDelegate
        x.CollectionView.RegisterClassForCell(typeof<ChatViewCell>, new NSString("ChatCell"))
    
    override x.ViewDidAppear(animated) = x.CollectionView.ReloadData()
    override x.NumberOfSections(collectionView : UICollectionView) = Conversions.nint(1)
    override x.GetItemsCount(collectionView : UICollectionView, section : nint) = Conversions.nint(listings.Length)

方案2:让控制器直接实现UICollectionViewDelegateFlowLayout接口

这种方式更简洁,不需要额外创建Delegate类,直接让你的LandlordHome控制器实现UICollectionViewDelegateFlowLayout接口,重写需要的方法即可:

[<Register ("LandlordHome")>]
type LandlordHome (handle:IntPtr) = 
    inherit UICollectionViewController (handle)
    // 实现UICollectionViewDelegateFlowLayout接口
    interface UICollectionViewDelegateFlowLayout with
        override x.GetSizeForItem(collectionView : UICollectionView, layout : UICollectionViewLayout, indexPath : NSIndexPath) = CGSize(100.0, 300.0)
    
    let addToList (listan:List<Listing>) (element:Listing) = element::listan
    let mutable listings : List<Listing> = List.Empty
    
    override x.ViewDidLoad () = 
        base.ViewDidLoad ()
        x.View.BackgroundColor <- UIColor.Gray
        for i in 1..10 do 
            let listing : Listing = new Listing(....code....)
            listings <- listing::listings
        x.CollectionView.BackgroundColor <- UIColor.Green
        // 不需要手动设置Delegate,控制器会自动作为Delegate
        x.CollectionView.RegisterClassForCell(typeof<ChatViewCell>, new NSString("ChatCell"))
    
    override x.ViewDidAppear(animated) = x.CollectionView.ReloadData()
    override x.NumberOfSections(collectionView : UICollectionView) = Conversions.nint(1)
    override x.GetItemsCount(collectionView : UICollectionView, section : nint) = Conversions.nint(listings.Length)

这种方式避免了单独管理Delegate实例的麻烦,也符合Xamarin iOS的开发习惯,推荐使用。

内容的提问来源于stack exchange,提问作者Alk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:44:59