Понимание создания пользовательского UITableCellView - загрузка из Nibs в MonoTouch - PullRequest
4 голосов
/ 26 марта 2012

Я использовал этот урок несколько раз: 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-файл в конструкторы? Почему необходимо создать два экземпляра ячейки? Что на самом деле происходит в фоновом режиме? Можно ли улучшить код?

Интересно узнать об этом, потому что я делаю это довольно часто, и я бы хотел сделать процесс чище

Stuart

Если это помогает, пример ячейки: https://github.com/slodge/MvvmCrossConference/blob/master/Cirrious.Conference.UI.Touch/Cells/SessionCell2.cs

1 Ответ

5 голосов
/ 28 марта 2012

Давайте посмотрим на вещи по одному.

Метод LoadNib разархивирует (и создает экземпляры) содержимое NIB. Первый параметр - это имя NIB, а второй параметр - владелец NIB, который будет загружен. То есть объект-заполнитель NIB "File's Owner", который, в данном случае, я полагаю, является просто объектом NSObject.

Метод LoadNib также возвращает NSArray объектов. Эти объекты являются объектами верхнего уровня NIB, в данном случае это пользовательская ячейка, созданная в NIB.

Полагаю, когда вы перемещаете код выше в конструкторе, вы реализуете что-то вроде этого:

public MyCustomCell() : base()
{
    NSBundle.MainBundle.LoadNib("MyCustomCell", this, null);
}

Если вы этого не сделаете, и ваша реализация отличается, но вы все еще используете LoadNib в конструкторе, выходы по-прежнему не удастся сохранить. Они созданы хорошо, но они не сохранены. Это не MonoTouch GC, который запускает или что-то еще, это нативная розетка, которая выпускается автоматически. Вы можете спросить: «Но почему я могу использовать LoadNib в конструкторе UIViewController и все еще получать мои розетки?». Это правильно, вы можете использовать LoadNib в конструкторе UIViewController, но есть одно важное отличие: этот 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 вне конструктора. Но, конечно, мы не можем сделать «это = что-то». Итак, подведем итоги создания LoadNib: ваш «MyCustomCell» является объектом верхнего уровня, и он предоставляется нам через возвращаемое значение LoadNib, а не путем передачи его в качестве владельца.

Следующая вещь, которую вы правильно заметили, касается двух случаев: я считаю, что это тоже неправильно. Посмотрите на ваш код выше, с некоторыми комментариями:

 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 является табличное представление. Представление таблицы будет обрабатываться средой выполнения (по крайней мере, в большинстве случаев).

Если вы все еще хотите использовать LoadNib внутри вашего класса MyCustomCell для создания экземпляра, просто создайте статический метод:

// 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:

Можете ли вы NIB это?

Руководство по программированию ресурсов Apple для файлов NIB

Надеюсь, это поможет.

...