Arm1.ru

Weak delegate в Swift 3

Боролся тут с утечками памяти в рабочем проекте. Копание привело к тому, что после ухода из UIViewController далеко не вся память освобождается. Если несколько раз открывать этот UIViewController, возвращаться назад и снова открывать - потребляемая память растёт и не очень слабо освобождается. 

Суть проблемы оказалась в протоколах и делегатах. У меня в UIViewController используется UICollectionView с кастомной ячейкой, у которой есть делегат. Мой UIViewController является для каждой ячейки делегатом. Пример реализации протокола и делегата в интернете и книге по Swift выгядит примерно так:

// Protocol
protocol MyCollectionViewCellDelegate {
  func someFunc()
}

// UICollectionViewCell
final class MessageCollectionViewCell: UICollectionViewCell {
  var delegate: MyCollectionViewCellDelegate?
}

// UIViewController
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  // some code....
  cell.delegate = self
}

Насколько я понял, внутри объекта ячейки получается strong-ссылка на делегата (UIViewController), в результате происходит утечка памяти.

Решение оказалось простое - чтобы сделать слабую ссылку, необходимо ограничить протокол так, чтобы ему удовлетворять мог только класс, и сделать слабую ссылку у проперти delegate. Структуры уже не смогут отвечать протоколу, но в моём случае этого и не нужно, я точно знаю, кто будет делегатом. Меняется всё так:

// Protocol
protocol MyCollectionViewCellDelegate: class {
  func someFunc()
}

// UICollectionViewCell
final class MessageCollectionViewCell: UICollectionViewCell {
  weak var delegate: MyCollectionViewCellDelegate?
}

После этих простых изменений всё стало прекрасно - после возвращения назад из UIViewController использование памяти возвращается на исходный уровень.

keyboard_return back