Я должен удалить подписки события из объектов, прежде чем они будут осиротевшими?

Это был единственный фрагмент кода, который работал для меня

Swift 4:

    tableView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
    tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
    tableView.setContentOffset(CGPoint(x: 0, y: -70), animated: true)

P.S. 70 - высота моего заголовка и ячейки табличного представления

23
задан Eric Anastas 2 July 2009 в 20:01
поделиться

3 ответа

Да, знаете. Издатели событий хранят ссылки на объекты и предотвращают их сборку мусора.

Давайте рассмотрим пример, чтобы увидеть, что происходит. У нас есть два класса; один раскрывает событие, другой потребляет его:

class ClassA
{
    public event EventHandler Test;
    ~ClassA()
    {
        Console.WriteLine("A being collected");
    }
}
class ClassB
{
    public ClassB(ClassA instance)
    {
        instance.Test += new EventHandler(instance_Test);
    }

    ~ClassB()
    {
        Console.WriteLine("B being collected");
    }

    void instance_Test(object sender, EventArgs e)
    {
        // this space is intentionally left blank
    }
}

Обратите внимание, как ClassB не хранит ссылку на экземпляр ClassA; он просто подключает обработчик событий.

Теперь давайте посмотрим, как собираются объекты. Сценарий 1:

ClassB temp = new ClassB(new ClassA());
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();

Мы создаем экземпляр ClassB и сохраняем ссылку на него через временную переменную. Ему передается новый экземпляр ClassA, где мы нигде не сохраняем ссылку на него, поэтому он выходит из области видимости сразу после завершения работы конструктора ClassB. У нас есть сборщик мусора, который запускается один раз, когда ClassA выходит из области видимости, и один раз, когда ClassB выходит из области видимости. Вывод:

Collect 1
A being collected
Collect 2
B being collected

Сценарий 2:

ClassA temp = new ClassA();
ClassB temp2 = new ClassB(temp);
temp2 = null;
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();

Создается новый экземпляр ClassA, и ссылка на него сохраняется во временной переменной. Затем создается новый экземпляр ClassB, которому передается экземпляр ClassA в temp, и мы сохраняем ссылку на него в temp2. Затем мы устанавливаем для temp2 значение null, в результате чего экземпляр ClassB выходит за пределы области видимости. Как и раньше, у нас запускается сборщик мусора после того, как каждый экземпляр выходит за пределы области видимости. Вывод:

Collect 1
Collect 2
B being collected
A being collected

Итак, в заключение; если экземпляр, отображающий событие, выходит за пределы области видимости, он становится доступным для сборки мусора, независимо от того, подключены ли обработчики событий или нет. Если экземпляр, у которого есть обработчик событий, подключенный к событию в другом экземпляре, он не будет доступен для сборки мусора до тех пор, пока обработчик событий не будет отсоединен,

23
ответ дан 29 November 2019 в 02:12
поделиться

Подписка на событие приводит к сильной ссылке на подписчика. Это связано с тем, что по сути события являются делегатами, а делегаты методов экземпляра представляют собой комбинацию ссылки на объект и фактического метода. Если вы не откажетесь от подписки, издатель продолжит поддерживать ссылки, а подписанные объекты никогда не станут по-настоящему осиротевшими (и GC'ed), пока жив издатель.

Обратное неверно, т.е. подписанные объект не имеет ссылки на издателя.

5
ответ дан 29 November 2019 в 02:12
поделиться

Отцеплять события нужно только в том случае, если объект , раскрывающий события, является долгоживущим, но объект , подключающий событие, в противном случае будет коротким жил (и довольно быстро собирать мусор).

В этом случае отказ от отключения вызовет утечку памяти, потому что ваш недолговечный объект не сможет быть собран в сборку мусора - потому что событие в длинном -lived объект удерживает делегат, который содержит ссылку на недолговечный объект. Поскольку этот делегат по-прежнему обращается к недолговечному объекту, он не может быть обработан сборщиком мусора.

Статические события долговечны по определению - они существуют до выхода из программы. Если вы перехватываете статическое событие, вам определенно следует отцепить его, когда вы закончите.

Если оба объекта вот-вот станут сиротами, отсоединение не требуется.

10
ответ дан 29 November 2019 в 02:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: