了解自定义 UITableCellView 的创建——从 MonoTouch 中的 Nibs 加载

Posted

技术标签:

【中文标题】了解自定义 UITableCellView 的创建——从 MonoTouch 中的 Nibs 加载【英文标题】:Understanding the creation of custom UITableCellView - loading from Nibs in MonoTouch 【发布时间】:2012-03-26 13:04:18 【问题描述】:

这个教程我用过好几次了:http://www.alexyork.net/blog/2011/07/18/creating-custom-uitableviewcells-with-monotouch-the-correct-way/

但是里面有一段代码我不是很理解:

    cell = new MyCustomCell();
    var views = NSBundle.MainBundle.LoadNib("MyCustomCell", cell, null);
    cell = Runtime.GetNSObject( views.ValueAt(0) ) as MyCustomCell;

我试图删除它 - 将 LoadNib 放置在构造函数中 - 但由于插座没有正确接线而出现问题。

谁能解释一下这里发生了什么?为什么我不能在构造函数中加载这个 Nib 文件?为什么需要实际创建两个单元实例?后台实际发生了什么?代码可以改进吗?

有兴趣了解这一点,因为我经常这样做,并且我希望使流程更清洁

斯图尔特

如果有帮助,示例单元格是:https://github.com/slodge/MvvmCrossConference/blob/master/Cirrious.Conference.UI.Touch/Cells/SessionCell2.cs

【问题讨论】:

我试图写一个完整的答案,但我仍然无法。有很多关于它的东西。简而言之:您不需要将单元中的插座连接到 NIB 中的文件所有者,并且您传递给 LoadNib(..) 的所有者应该声明插座。我目前正在写一篇关于 NIB 加载的文章,我相信这可以解释很多。在那之前,检查我创建的示例项目:github.com/dtavlikos/JTNibManager 谢谢。期待博文和学习。我更愿意为您提供 sib 编辑器,但目前我发现整个过程有点混乱(也可能有问题) 【参考方案1】:

让我们一次看一件事情。

LoadNib 方法取消归档(并实例化)NIB 的内容。第一个参数是 NIB 的名称,第二个参数是要加载的 NIB 的所有者。也就是说,NIB 的“文件所有者”占位符对象,在这种情况下,我想它只是一个 NSObject。

LoadNib 方法还返回一个对象的 NSArray。这些对象是 NIB 的***对象,在本例中,是您在 NIB 中创建的自定义单元格。

我想当你在构造函数中移动上面的代码时,你实现了这样的东西:

public MyCustomCell() : base()

    NSBundle.MainBundle.LoadNib("MyCustomCell", this, null);

如果您不这样做,并且您的实现有所不同,但您仍在构造函数中使用 LoadNib,则仍然无法保留插座。它们可以被创建,但不会被保留。启动的不是 MonoTouch GC 或其他任何东西,而是自动发布的本地出口。您可能想知道“但为什么我可以在 UIViewController 的构造函数中使用 LoadNib 并仍然获得我的插座?”。没错,您可以在 UIViewController 的构造函数中使用 LoadNib,但有一个重要区别: UIViewController 是您的文件所有者占位符对象。如果您尝试对不是文件所有者的控制器执行相同操作,则在保留出口方面会遇到同样的失败。

LoadNib 方法基本上需要的是***对象的返回数组。因此,要使其在构造函​​数中工作,“正确”的方式是:

    public MyCustomCell() : base()
    
        NSArray arr = NSBundle.LoadNib("MyCustomCell", this, null);
        this = Runtime.GetNSObject(arr.ValueAt(0)); // should retain everything,
        //BUT: Compile error!
    

这基本上与您在构造函数之外加载 NIB 所做的事情相同。但是当然,我们不能做“this = something”。因此,总结一下 LoadNib 的创建:您的“MyCustomCell”是一个***对象,它是通过 LoadNib 的返回值提供给我们的,而不是作为所有者传递给我们的。

接下来您正确注意到的是关于这两个实例:我认为这也是错误的。看看你上面的代码,有一些 cmets:

 cell = new MyCustomCell(); // Created a new instance of MyCustomCell
 var views = NSBundle.MainBundle.LoadNib("MyCustomCell", cell, null); // Assigned it as an owner
 cell = Runtime.GetNSObject( views.ValueAt(0) ) as MyCustomCell; // What happens to the owner?

我认为这是内存泄漏。但请考虑以下几点:

// Not needed
//cell = new MyCustomCell(); 
var views = NSBundle.MainBundle.LoadNib("MyCustomCell", tableView, null); // Owner is now the tableView
cell = Runtime.GetNSObject( views.ValueAt(0) ) as MyCustomCell;
views = null; // Don't need it anymore

NIB 的所有者现在是表视图。表格视图将由运行时处理(至少在大多数情况下)。

如果您仍想在 MyCustomCell 类中使用 LoadNib 来创建实例,只需创建一个静态方法:

// Inside MyCustomCell
public static MyCustomCell CreateCell(NSObject owner)

    NSArray topLevelObjects = NSBundle.MainBundle.LoadNib("MyCustomCell", owner, null);
    MyCustomCell customCell = Runtime.GetNSObject(topLevelObjects.ValueAt(0)) as MyCustomCell;
    topLevelObjects = null;
    return customCell;

有关NIB加载的更多信息:

Can you NIB it?

Apple's Resource Programming Guide on NIB files

我希望这会有所帮助。

【讨论】:

Dimitri,很好的答案,刚刚发表了评论。我不确定设置 views = nulltopLevelObjects = null 是否有帮助。如果它们是局部变量,则不必将它们设置为 null——它们会被 GC 处理,没有问题。我喜欢你的“你能NIB吗?”文章,我自己也想知道这些东西的内部结构。 嗨乔纳森。你是对的,只是我最近一直在阅读许多 ObjC 的东西。至于NIB加载,我正在准备更多的东西,敬请期待......;) 是的,我在 C# 领域工作了这么久,我认为这是理所当然的。我不确定我是否会在 Obj-C 世界中取得成功。

以上是关于了解自定义 UITableCellView 的创建——从 MonoTouch 中的 Nibs 加载的主要内容,如果未能解决你的问题,请参考以下文章

如何阻止 UILabel 在 UITableCellView 中用“...”截断

带有子视图的可变 UITableCellView 高度

如何捕获 UIButton 事件:在自定义 UITableViewCell 实现中添加了 UIButton

为 UITableCellView 中的视图添加 NSLayoutConstraint

为啥我在 UITableCellView 中的 UIView 中的 UILabel 在正确的数据库调用后没有更新(似乎与单元重用有关)?

试图了解 Boost.Asio 自定义服务实现