NSObject не вызывает делегатов других классов - PullRequest
0 голосов
/ 06 февраля 2020

У меня довольно простой класс NSObject, который я называю MediaPicker. Этот класс спрашивает пользователя, какой тип носителя он хочет выбрать, и затем представляет UIImagePickerController или UIDocumentPickerViewController на основе своего выбора.

Проблема, с которой я сталкиваюсь, заключается в том, что методы UIImagePickerControllerDelegate и UIDocumentPickerViewControllerDelegate не вызываются.

Мой класс ниже:

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 для MediaPickerDelegate и class и NSObjectProtocol, но безуспешно. Я также попытался (подумав, может быть, проблема AR C из моего obj- c дней) сделать две переменные средства выбора глобальными и локальными по объему для функции, но, похоже, это ничего не изменило.

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

Ответы [ 2 ]

0 голосов
/ 06 февраля 2020

Хорошо, я провел некоторое тестирование / настройку и понял, что оба контроллера выбора документов / изображений удаляются из памяти, как только они отображаются. Это потому, что они локальны для области функции, которая их вызывает, и функция завершила выполнение.

Я имею в виду, что в функции openPicker (из вопроса) класс, который является вызывая его, вы делаете AR C magi c и удаляете его, как только он думает, что вызов функции завершен. Поскольку mediaPicker является локальным для openPicker и не глобальным для class Foo, он не понимает, что ему нужно хранить его в памяти.

Решение здесь состоит в том, чтобы иметь глобальную переменную в классе уровень внутри class Foo и доступ к нему внутри функции openPicker вместо инициализации нового экземпляра MediaPicker следующим образом:

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

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

Как только я перешел на использование этого подхода, делегаты вызывают и отладчик ясно показывает, что объект сохраняется в памяти, в то время как class / UIViewController все еще интерактивно доступен для пользователя.

0 голосов
/ 06 февраля 2020

Пытались получить разрешение для библиотеки фотографий (конфиденциальность - описание использования библиотеки фотографий) в Info.plist?

...