我有一个相当简单的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
的{{1}}和MediaPickerDelegate
都设为class
,但是没有运气。我还尝试了(考虑到我的obj-c时代的ARC问题),使两个选择器变量在作用域内成为全局和局部范围,但这似乎没有任何改变。
对于您所写的代码质量/我可能错过的最佳实践,我也欢迎您提出任何反馈意见。
答案 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中获得照片库(隐私-照片库使用说明)的许可?