在Monotouch中将分段控件单击到UITableViewCell会导致SIGABRT

在Monotouch中将分段控件单击到UITableViewCell会导致SIGABRT,uitableview,xamarin.ios,sigabrt,Uitableview,Xamarin.ios,Sigabrt,在我的iPhone Monotouch应用程序中,我试图向UITableViewCell添加一个分段控制器,作为每行中某个值的切换。所有内容都正确显示,单击时,第一行最初将正常工作。但是,在该行离开屏幕并重新加载后,如果我再次单击分段控制器,我将收到一个异常: 由于未处理的异常正在终止运行时 [错误]致命的未处理异常:System.EXCEPTION:从objective-c对已GC'ed的类型为MonoTouch.UIKit.UIControlEventProxy(0x16D793C0)的托管

在我的iPhone Monotouch应用程序中,我试图向UITableViewCell添加一个分段控制器,作为每行中某个值的切换。所有内容都正确显示,单击时,第一行最初将正常工作。但是,在该行离开屏幕并重新加载后,如果我再次单击分段控制器,我将收到一个异常:

由于未处理的异常正在终止运行时 [错误]致命的未处理异常:System.EXCEPTION:从objective-c对已GC'ed的类型为MonoTouch.UIKit.UIControlEventProxy(0x16D793C0)的托管对象调用选择器---->System.MissingMethodException:未找到MonoTouch.UIKit.UIControlEventProxy::.ctor(System.IntPtr)的构造函数

我听说过类似的问题,人们使用Monotouch试图在表格单元格中放置按钮。一般的建议是将每个表单元添加到列表中,以防止其被垃圾收集,但这对我来说并不奏效

有解决这个问题的办法吗

下面是我的GetCell代码的简化版本:

public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
        {

            Hashtable rowData = dataList [indexPath.Row];
            FilterListToggleCell cell;
            cell = (FilterListToggleCell)tableView.DequeueReusableCell ("FilterTogglePlusCell");


            cacheList.Add(cell.Toggle);//cache only the segcontrol
                            //cacheList.Add(cell);//also previously tried caching the whole cell


            cell.Title.Text = (string)rowData["title"];
            if(additionalFields.Contains((string)rowData["key"])){
                cell.Toggle.SelectedSegment = 0;
            } else {
                cell.Toggle.SelectedSegment = 1;

            }



            cell.Toggle.ValueChanged += (sender, e) => {
                UISegmentedControl toggle = (UISegmentedControl)sender;

                if(toggle.SelectedSegment == 0){
                    Console.WriteLine("Toggle YES");
                } else {
                    Console.WriteLine("Toggle NO");
                }

            };



            cell.Toggle.Tag = indexPath.Row;

            return cell;

        }
基本情况你说得对。出现这种情况是因为没有对从
GetCell
方法返回的
UITableViewCell
managed引用。因此,GC可以收集并释放它(这将导致一些问题,比如想要回调托管实例的事件)。有关更多详细信息,请参见此

现在我不知道为什么这种方法不适合你。但是,上面的代码似乎不完整,例如

cell = (FilterListToggleCell)tableView.DequeueReusableCell ("FilterTogglePlusCell");
可以返回
null
,此时您应该创建更多的单元格(事实上,没有实际创建任何新单元格的条件,因此没有可重复使用的内容)

单元格
为空时(因为
单元格.Toggle
),下一行将抛出
NullReferenceException


请注意,这并不能解释您的崩溃-我怀疑有一些丢失的代码使其正常工作(创建单元格),并且可能无法正确缓存它们。

基于此问题的信息,我能够在不需要额外缓存的情况下使其正常工作:

ValueChanged行已替换为:

cell.Toggle.AddTarget(this, new Selector("ToggleChange"),UIControlEvent.ValueChanged);
我的UITableViewDataSource中添加了另一个方法

[Export ("ToggleChange")]
void OnChange(UISementedControl toggle){
    if(toggle.SelectedSegment == 0){
        Console.WriteLine("Toggle YES");
    } else {
        Console.WriteLine("Toggle NO");
    }
}

上述代码中的问题(即使在缓存托管单元格时)可能是由“cell.Toggle.ValueChanged+=(sender,e)”引起的。如果单元格已经被使用,第二次它将有两个事件处理程序,第三次它将有三个事件处理程序,依此类推。但是,前面的处理程序将引用一个可能现在不再有效的cell/UISegmentedControl并崩溃。我建议使事件处理程序不是匿名的,而是一个真实的方法,并通过调用“cell.Toggle.ValueChanged-=MyHandler;cell.Toggle.ValueChanged+=MyHandler;”在重新分配它之前将其删除。好的观点是多个事件处理程序。通常,事件仅在创建单元时设置,而不是在重新使用单元时设置。