Ячейка не освобождается после закрытия представления таблицы, на которую ссылается контекст закрытия - PullRequest
0 голосов
/ 04 мая 2020

Я создаю настраиваемую ячейку табличного представления, которая позволяет пользователю добавлять, снимать или просматривать загруженные фотографии.

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

График показывает, что на мою ячейку сильно ссылается addPhotoTapAction. context .

addPhotoTapAction: ((ItemInfoCell) -> Void)? - это переменная класса ячейки, используемая для хранения пользовательского ввода, обрабатывающего закрытие. Замыкание определяется в контроллере представления:

let infocell = tableView.dequeueReusableCell(withIdentifier: K.infocellID) as! ItemInfoCell
    if item?.imageUrl == nil {
        self.imageManager.actionController?.actions[2].isEnabled = false
    } else {
        self.imageManager.actionController?.actions[2].isEnabled = true
    }
    infocell.addPhotoTapAction = { [unowned self] _ in
        infocell.addPhotoButton.isEnabled = false
        self.imageManager.pickImage(self) { [weak self] image in
            self?.imageToSave = image
            infocell.itemPhoto.image = self?.imageToSave
            infocell.addPhotoButton.tintColor = UIColor(ciColor: .clear)
            infocell.addPhotoButton.isEnabled = true
            self?.imageManager.actionController?.actions[2].isEnabled = true
        }

Метод pickImage показан ниже. Он используется для представления контроллера действий с параметрами выбора изображения (сфотографировать или выбрать из библиотеки):

func pickImage(_ viewController: UIViewController, _ callback: @escaping ((UIImage) -> ())) {
    picker.delegate = self
    picker.mediaTypes = ["public.image"]
    picker.allowsEditing = true
    pickImageCallback = callback
    self.viewController = viewController
    actionController!.popoverPresentationController?.sourceView = viewController.view
    viewController.present(actionController!, animated: true, completion: nil)
}

... и обратный вызов сохраняется для использования в вызове средства выбора didFinishPickingMediaWithInfo :

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true, completion: nil)
    if let image = info[.editedImage] as? UIImage {
        let squareImage = makeSquare(image)
        pickImageCallback?(squareImage)
    } else if let image = info[.originalImage] as? UIImage {
        let squareImage = makeSquare(image)
        pickImageCallback?(squareImage)
    }
    viewController = nil
}

Я попытался вручную установить переменную с закрытием на nil , затем переключился с [weak self] на [unowned self] на их комбинацию. Не повезло.

Я думаю, что либо pickImage (self) , либо использование свойств класса в замыкании создают сильную ссылку даже при использовании списков захвата [weak / unowned], но я все еще не уверен и не могу это исправить.

Обновление: код класса ItemInfoCell

class ItemInfoCell: UITableViewCell {

@IBOutlet weak var itemPhoto: UIImageView!
@IBOutlet weak var itemLabel: UILabel!
@IBOutlet weak var addPhotoButton: UIButton!

var addPhotoTapAction: ((ItemInfoCell) -> Void)?

override func awakeFromNib() {
    super.awakeFromNib()
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
}

@IBAction func takePhoto(_ sender: Any) {
    if let addPhoto = self.addPhotoTapAction {
        addPhoto(self)
    }
}

}

Ответы [ 2 ]

0 голосов
/ 28 мая 2020

В вашем коде есть сильная ссылка от инфоячейки на закрытие и внутреннее закрытие, на которое вы ссылаетесь на информационную ячейку, т.е. оба имеют сильную ссылку друг на друга.

infocell.addPhotoTapAction = { [unowned self] _ in
    infocell.addPhotoButton.isEnabled = false
     ...
}

Это приводит к циклу сохранения и не позволяет освободить ячейку.

Поскольку вы уже используете список захвата для себя, вы можете легко решить эту проблему, добавив информационную ячейку в список захвата, например:

infocell.addPhotoTapAction = { [weak self, weak infocell] _ in
    guard let self = self else { return }
    infocell.addPhotoButton.isEnabled = false
    ...
}

Вообще говоря, рекомендуется использовать unowned только тогда, когда вы полностью уверены, что ссылка не станет nil до выполнения закрытия, потому что использование unowned похоже на принудительное развертывание необязательного значения. Если это nil, ваше приложение выдаст sh. Так что weak self обычно более безопасный способ набрать go.

0 голосов
/ 05 мая 2020

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

В вашем коде это должно быть так:

   infocell.addPhotoTapAction = { [unowned self, weak infocell] _ in
      ...
    }
...