ios - 代表保留圈虽然使用弱
问题描述
我正在与协调员一起工作。即使我设置了弱委托,我的 ViewController 也没有解除分配。
协调员:
class JournalDetailCoordinator: Coordinator {
var dependencys: AppDependency
var navigationController: UINavigationController
var collectionViewController: CollectionViewWithMenuController!
var imagePickerManager: ImagePickerManager!
init(dependencys: AppDependency, navigationController: UINavigationController) {
self.dependencys = dependencys
self.navigationController = navigationController
}
func start() {
loadCollectionViewController()
}
deinit {
print("JournalDetailCoordinator deinitialisiert")
}
func loadCollectionViewController() {
var journalDetailViewControllerContainer = [JournalDetailViewController]()
for journal in dependencys.journals {
let vc: JournalDetailViewController = dependencys.getJournalDetailDependency().createVC()
vc.entryJournal = journal
vc.delegateLoadImagePickerManager = self
journalDetailViewControllerContainer.append(vc)
}
collectionViewController = dependencys.getCollectionViewWithMenuDependency().createVC()
collectionViewController.managedViewControllers = journalDetailViewControllerContainer
navigationController.pushViewController(collectionViewController, animated: true)
}
}
extension JournalDetailCoordinator: LoadImagePickerManager {
func loadImagePickerManager<T>(vc: T) where T : UIViewController & ImageGetterDelegate {
imagePickerManager = ImagePickerManager()
imagePickerManager.delegate = vc
imagePickerManager.pickImage(viewController: collectionViewController)
}
}
视图控制器:
class JournalDetailViewController: UIViewController {
lazy var mainView: JournalDetailViewP = {
let view = JournalDetailViewP()
return view
}()
typealias myType = SetJournal & HasImagePickerManager
// dependency
var dep: myType!
var entryJournal: Journaling!
var tableViewDataSource: JournalDetailTVDataSource?
var collectionViewInteraction: AddImageCollectionViewInteraction?
weak var delegateLoadImagePickerManager: LoadImagePickerManager?
override func viewDidLoad() {
super.viewDidLoad()
title = "Detail Journal"
// only for testing without coordinator connection
// if entryJournal == nil {
// entryJournal = NewJournal()
// }
// dep = AppDependency()
setMainView()
loadTableView()
loadCollectionView()
}
override func viewDidDisappear(_ animated: Bool) {
print("view did disappear Journal Detail")
}
deinit {
dep.setJournal(newJournal: entryJournal)
print("JournalDetailViewController deinitialisiert")
}
@objc func getImage() {
delegateLoadImagePickerManager?.loadImagePickerManager(vc: self)
// dep.imagePickerManager.delegate = self
// dep.imagePickerManager.pickImage(viewController: self)
}
func saveEntry() {
}
}
extension JournalDetailViewController: Storyboarded {}
extension JournalDetailViewController: DependencyInjectionVC {}
extension JournalDetailViewController: SetMainView {}
extension JournalDetailViewController: ImageGetterDelegate {
func returnImage(image: UIImage) {
if entryJournal.image[0] == nil {
entryJournal.image[0] = image
} else {
entryJournal.image.append(image)
}
loadCollectionView()
}
}
extension JournalDetailViewController: AddImageCollectionViewInteractionDelegate {
func deleteImage(index: Int) {
}
func addImage() {
getImage()
}
}
如果我不执行 getImage() 函数,它们就会被释放,所以我认为这是保留圈的原因。
这就是 ImagePickerManager:
protocol ImageGetterDelegate: class {
func returnImage(image: UIImage)
}
class ImagePickerManager: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var imagePicker = UIImagePickerController()
weak var delegate: ImageGetterDelegate?
override init() {
super.init()
print("ImagePickerManager initialisiert")
}
deinit {
print("imagePickerManager deinitialisiert")
}
/// use to pick the Image, make sure to use the root ViewController to pass in to
func pickImage<T:UIViewController>(viewController: T) {
let alertList = UIAlertController(title: NSLocalizedString("Load Picture", comment: "Picture alert Alertcontroller"), message: nil, preferredStyle: .actionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: .default) {
UIAlertAction in self.openCamera(viewController: viewController)
alertList.dismiss(animated: true, completion: nil)
}
let galleryAction = UIAlertAction(title: "Gallery", style: .default) {
UIAlertAction in self.openGallery(viewController: viewController)
alertList.dismiss(animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) {
UIAlertAction in
alertList.dismiss(animated: true, completion: nil)
}
alertList.addAction(cameraAction)
alertList.addAction(galleryAction)
alertList.addAction(cancelAction)
viewController.present(alertList, animated: true, completion: nil)
}
private func openCamera<T:UIViewController>(viewController: T) {
if(UIImagePickerController .isSourceTypeAvailable(.camera)) {
imagePicker.sourceType = .camera
imagePicker.delegate = self
viewController.present(imagePicker, animated: true, completion: nil)
} else {
let warningAlert = UIAlertController(title: "Warning", message: "You do not have a camera", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Okay", style: .cancel) {
UIAlertAction in
warningAlert.dismiss(animated: true, completion: nil)
}
warningAlert.addAction(cancelAction)
viewController.present(warningAlert, animated: true, completion: nil)
}
}
private func openGallery<T:UIViewController>(viewController: T) {
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
viewController.present(imagePicker, animated: true, completion: nil)
}
@objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[.originalImage] as? UIImage else {
print("Expected a dictionary containing an image, but was provided the following: \(info)")
return
}
delegate?.returnImage(image: image)
}
}
ImagePickerManager 在 Coordinator 被释放后没有分配。所以我认为保留圈是因为我将 ViewVontroller 传递回 LoadImagePickerManager 中的 Coordinator,然后将 vc 设置为 Coordinator?有没有人知道如何解决这个问题或该怎么做?
编辑:LoadImagePickerManager:
protocol LoadImagePickerManager: class {
func loadImagePickerManager<T: UIViewController & ImageGetterDelegate>(vc: T)
}
我认为传递collectionViewController时发生内存泄漏:
imagePickerManager.pickImage(viewController: collectionViewController)
因为如果我不执行这部分,我做了一些测试,那么一切都很好。
更新了 ImagePickerManager 类:
class ImagePickerManager: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var imagePicker = UIImagePickerController()
weak var delegate: ImageGetterDelegate?
var viewController: UIViewController!
override init() {
super.init()
print("ImagePickerManager initialisiert")
}
deinit {
print("imagePickerManager deinitialisiert")
}
/// use to pick the Image, make sure to use the root ViewController to pass in to
func pickImage<T:UIViewController>(viewController: T) {
self.viewController = viewController
let alertList = UIAlertController(title: NSLocalizedString("Load Picture", comment: "Picture alert Alertcontroller"), message: nil, preferredStyle: .actionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: .default) {
UIAlertAction in self.openCamera()
alertList.dismiss(animated: true, completion: nil)
}
let galleryAction = UIAlertAction(title: "Gallery", style: .default) {
UIAlertAction in self.openGallery()
alertList.dismiss(animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) {
UIAlertAction in
alertList.dismiss(animated: true, completion: nil)
}
alertList.addAction(cameraAction)
alertList.addAction(galleryAction)
alertList.addAction(cancelAction)
viewController.present(alertList, animated: true, completion: nil)
}
private func openCamera() {
if(UIImagePickerController .isSourceTypeAvailable(.camera)) {
imagePicker.sourceType = .camera
imagePicker.delegate = self
viewController.present(imagePicker, animated: true, completion: nil)
} else {
let warningAlert = UIAlertController(title: "Warning", message: "You do not have a camera", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Okay", style: .cancel) {
UIAlertAction in
warningAlert.dismiss(animated: true, completion: nil)
}
warningAlert.addAction(cancelAction)
viewController.present(warningAlert, animated: true, completion: nil)
}
}
private func openGallery() {
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
viewController.present(imagePicker, animated: true, completion: nil)
}
@objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[.originalImage] as? UIImage else {
print("Expected a dictionary containing an image, but was provided the following: \(info)")
return
}
viewController = nil
delegate?.returnImage(image: image)
}
}
我在类中添加了一个ViewController变量,并通过Pickimage()将其设置为“绘制”,然后选择图像时,我将变量设置为nil。然后 UIViewController 被释放,但 ImagePickerManager 类仍然保持活动状态并且没有被分配。
解决方案
由于您使用的是弱委托,因此绝不会创建保留周期。
我认为您的 viewController 没有解除分配,因为您的 viewController 仍在导航堆栈中。
尝试从导航堆栈中删除所有 viewController,然后您的 deallocate 块将照常工作。
当您返回 homeViewController 时,根据您的要求(呈现/推送)尝试以下代码:
self.navigationController?.popToRootViewController(animated: true)
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
编辑:
确保您的协议是类类型,然后只有弱引用才能工作。
protocol LoadImagePickerManager: class {
}
在您的 PickerManager 中尝试使用以下代码关闭,它会将您重定向到 rootview 控制器,但您可以再次推送或呈现到所需的视图控制器:
self.view.window?.rootViewController?.dismiss(animated: false, completion: nil)
推荐阅读
- java - EqualsIngnoreCase 的过滤谓词
- javascript - dragscroll.js 阻止显示工具提示?
- excel - 我正在尝试创建一个从单元格填充组合框选项的用户表单。我怎么能只从单元格范围中提取唯一值?
- esp32 - 运行在 240MHz 的 esp32 似乎有一个 160MHz 的时钟。哪个是真相?
- c++ - 从朋友类的朋友功能访问私人成员
- javascript - 无论屏幕大小如何 javasript 如何获取鼠标位置
- unity3d - 有没有办法使用 Photon Pun2 或 Photon Chat 发送或接收图像、音频和视频?
- tensorflow - Tensorflow 2 中的字符串比较:不允许使用 `tf.Tensor` 作为 Python `bool`:AutoGraph 确实转换了此函数
- r - svd(x, nu = 0, nv = k) 中的错误:“x”中的值无限或缺失。矩阵中没有 NA 或 Inf 值
- javascript - MiniCssExtractPlugin 的 linkType 和 html-webpack-link-type-plugin 都不起作用