委托保留圈,尽管使用弱

时间:2019-03-04 05:53:45

标签: ios swift memory-leaks delegates

我正在与协调员一起工作。 即使设置了弱的委托,我的ViewController也不会取消分配。

协调员:

<table class="table-a" width="200">
  <tr>
    <td>Foo</td>
    <td>Bar</td>
  </tr>
</table>

<table class="table-b" width="200">
  <tr>
    <td>Foo</td>
    <td>Bar</td>
  </tr>
</table>

<table class="table-b">
  <tr>
    <td>Foo</td>
    <td>Bar</td>
  </tr>
</table>

<p>Table A seems to show that the width attribute will not override external stylesheets the same way inline stylesheets.</p>

<p>Is there a way to ensure that when a width attribute is not passed to a table, that it defaults to 100%, and otherwise adheres to the width declaration/</p>

ViewController:

class EventEmitter {

    private static $events = array(); // all subscriptions

    public function __construct() {}

  // calls the last subscription on the stack

    public function emit() {

    }

  // adds subscriptions to the stack

    public function subscribe($name, $callback) {

      if(empty(self::$events[$name]))
        self::$events[$name] = array();

      array_push(self::$events[$name], $callback);
    }

}

$emitter = new EventEmitter;

$error_callback = function($data) {
    echo "Error 1. {$data["message"]} \n";
};

$error_callback2 = function($data) {
    echo "Error 2. {$data["message"]} \n";
};

$success_callback = function($data) {
    echo "SUCCESS! {$data["message"]} \n";
};

如果我不执行getImage()函数,它们将被释放,因此我认为这是保留周期的原因。

那就是ImagePickerManager:

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)

    }
}

在释放协调器后,ImagePickerManager没有分配。所以我认为保留圈是因为我将ViewVontroller传递回LoadImagePickerManager中的协调器,然后将vc设置为协调器?是否有人知道如何解决该问题或怎么办?

编辑: LoadImagePickerManager:

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()
    }
}

我认为传递collectionViewController时会在这里发生内存泄漏:

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

protocol LoadImagePickerManager: class {
    func loadImagePickerManager<T: UIViewController & ImageGetterDelegate>(vc: T)
}

我在类中添加了一个viewController变量,并通过pickImage()进行设置,然后在选择图像时将变量设置为nil。然后,UIViewController被释放,但是ImagePickerManager类仍然处于活动状态,并且没有被分配。

1 个答案:

答案 0 :(得分:0)

由于您使用的是弱委托,因此绝不会创建保留周期。

我认为您的viewController没有取消分配,因为您的viewController仍在导航堆栈中。

尝试从导航堆栈中删除所有viewControllers,然后您的deallocate块将照常工作。

当您返回homeViewController时,请根据您的要求(演示/推送)尝试以下代码:

void Edge::on_slotDelete_clicked()
{
    QSettings settings("slots.ini",QSettings::IniFormat);

    QString slotText;

    QList<QListWidgetItem*> items = ui->slotList->selectedItems();
    foreach(QListWidgetItem* item, items)
    {
        ui->slotList->removeItemWidget(item);
        slotText.append(item->text());//this grabs the name
        delete item;// this deletes list item
    }

    settings.beginGroup(slotText);// only takes QString or const QString argument
    settings.remove("");
    settings.endGroup();

    qDebug() << slotText;
}

编辑:

确保您的协议是类类型,然后只有弱引用才能起作用。

self.navigationController?.popToRootViewController(animated: true)

self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)

在您的PickerManager中尝试使用以下代码关闭,它将重定向您到rootview控制器,但是您可以再次将其推送或呈现给所需的viewcontroller:

protocol LoadImagePickerManager: class {

}