NSObject不调用其他类的委托

时间:2020-02-06 04:56:33

标签: ios swift nsobject

我有一个相当简单的NSObject类,我称之为MediaPicker。此类询问用户他们想要选择哪种类型的媒体,然后根据他们的选择显示UIImagePickerControllerUIDocumentPickerViewController

我面临的问题是UIImagePickerControllerDelegateUIDocumentPickerViewControllerDelegate方法没有被调用。

我的课在下面:

import Foundation
import UIKit
import MobileCoreServices

public protocol MediaPickerDelegate: NSObjectProtocol {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any])
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController)
    func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController)
    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL])
}

class MediaPicker: NSObject {
    //Data
    var viewController: UIViewController? = nil
    var imagePicker: UIImagePickerController = UIImagePickerController()
    let documentPicker = UIDocumentPickerViewController(documentTypes: [(kUTTypeImage as String), (kUTTypeMovie as String)], in: .import)

    //Delegate
    weak var delegate: MediaPickerDelegate? = nil

    override init() {
        super.init()
    }

    public func showMediaPicker(from presentingViewController: UIViewController) {
        //Set Data
        self.viewController = presentingViewController

        //Create Alert
        let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        //Add Library Action
        let libraryAction: UIAlertAction = UIAlertAction(title: "Photo & Video Library", style: .default) { (action) in
            self.presentLibraryPicker()
        }
        libraryAction.setValue(UIImage(named: "gallery_picker_library"), forKey: "image")
        libraryAction.setValue(CATextLayerAlignmentMode.left, forKey: "titleTextAlignment")
        alertController.addAction(libraryAction)

        //Add Cloud Action
        let cloudAction: UIAlertAction = UIAlertAction(title: "Other Locations", style: .default) { (action) in
            self.presentDocumentPicker()
        }
        cloudAction.setValue(UIImage(named: "gallery_picker_cloud"), forKey: "image")
        cloudAction.setValue(CATextLayerAlignmentMode.left, forKey: "titleTextAlignment")
        alertController.addAction(cloudAction)

        //Add Cancel Action
        let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        alertController.addAction(cancelAction)

        //Show Alert
        self.viewController?.present(alertController, animated: true, completion: nil)
    }

    private func presentLibraryPicker() {
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary
        imagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .savedPhotosAlbum) ?? []
        imagePicker.allowsEditing = true
        self.viewController?.present(imagePicker, animated: true, completion: nil)
    }

    private func presentDocumentPicker() {
        documentPicker.delegate = self
        documentPicker.allowsMultipleSelection = false
        self.viewController?.present(documentPicker, animated: true, completion: nil)
    }
}

extension MediaPicker: UIImagePickerControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
        delegate?.imagePickerController(picker, didFinishPickingMediaWithInfo: info)
    }

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        delegate?.imagePickerControllerDidCancel(picker)
    }
}

extension MediaPicker: UIDocumentPickerDelegate {
    func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
        delegate?.documentPickerWasCancelled(controller)
    }

    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        delegate?.documentPicker(controller, didPickDocumentsAt: urls)
    }
}

extension MediaPicker: UINavigationControllerDelegate {
    //Redundant delegate implented as part of UIImagePickerControllerDelegate
}

调用该类的类如下:

class Foo: UIViewController {

    @objc func openPicker() {
        let mediaPicker: MediaPicker = MediaPicker()
        mediaPicker.delegate = self
        mediaPicker.showMediaPicker(from: self)
    }
}

我尝试将protocol的{​​{1}}和MediaPickerDelegate都设为class,但是没有运气。我还尝试了(考虑到我的obj-c时代的ARC问题),使两个选择器变量在作用域内成为全局和局部范围,但这似乎没有任何改变。

对于您所写的代码质量/我可能错过的最佳实践,我也欢迎您提出任何反馈意见。

2 个答案:

答案 0 :(得分:0)

好,所以我进行了一些测试/调整,并意识到,两个文档/图像选择器控制器在显示后都会立即从内存中删除。这是因为它们在调用它们的函数的作用域内是本地的,并且该函数已完成执行。

我的意思是,在函数openPicker中(从问题中),正在调用它的类正在做某种ARC魔术,并在认为函数被调用完成后立即将其删除。由于mediaPicker对于openPicker是本地的,而对于class Foo不是全局的,因此它不了解需要将其保存在内存中。

这里的解决方案是在class Foo内部的类级别具有全局变量,并在函数openPicker内部访问该全局变量,而不是按如下方式初始化MediaPicker的新实例: / p>

class Foo: UIViewController {
    //Data
    var mediaPicker: MediaPicker = MediaPicker()

    @objc func openPicker() {
        self.mediaPicker.delegate = self
        self.mediaPicker.showMediaPicker(from: self)
    }
}

一旦我迁移到使用这种方法,就会调用委托,并且调试器清楚地表明对象仍保留在内存中,而class / UIViewController仍可供用户交互使用。

答案 1 :(得分:-2)

是否已尝试在Info.plist中获得照片库(隐私-照片库使用说明)的许可?