How can I assign a delegate for UIVideoEditorController in ReactNative when the module I am working on is just classes - ios

func previewRecording (withFileName fileURL: String) {
if UIVideoEditorController.canEditVideo(atPath: fileURL) {
let rootView = UIApplication.getTopMostViewController()
let editController = UIVideoEditorController()
editController.videoPath = fileURL
// editController.delegate = ?????
rootView?.present(editController, animated: true, completion: nil)
} else {
}
}
^ current code
I have gone around the internet in circles a few times trying to figure this out. What would be the best approach for specifying a delegate for the UIVideoEditorController here? This is a react-native module where there is no ViewController, just utility classes.
Some simple example code I have come across
extension SomeViewController :
UIVideoEditorControllerDelegate,
UINavigationControllerDelegate {
func videoEditorController(_ editor: UIVideoEditorController,
didSaveEditedVideoToPath editedVideoPath: String) {
print("saved!")
}
}
I am just loss about how to make this happen in my module though.

#objc class ScreenRecordCoordinator: NSObject
{
let previewDelegateView = PreviewDelegateView()
// .......
editController.delegate = previewDelegateView
}
class PreviewDelegateView: UIViewController, UINavigationControllerDelegate, UIVideoEditorControllerDelegate {
var isSaved:Bool = false
func videoEditorController(_ editor: UIVideoEditorController, didSaveEditedVideoToPath editedVideoPath: String) {
print("save called")
if(!self.isSaved) {
self.isSaved = true
print("trimmed video saved!")
editor.dismiss(animated: true, completion: {
ReplayFileUtil.replaceItem(at: URL(fileURLWithPath: editor.videoPath), with: URL(fileURLWithPath: editedVideoPath))
self.isSaved = false
})
}
}
}

Related

Is there a delegate method that gets called before the UIDocumentInteractionController share sheet pop ups

Please can someone help.I would like to add an alert message once a user clicks on the share button on a pdf viewer, i'm using UIDocumentInteractionController to preview the pdf document. and i wanted to know if there are any delegate methods or functions that i can override, where i can add my alert before opening the sharing sheet?[![enter image description here][1]][1]
class ViewController: UIViewController {
var documentController : UIDocumentInteractionController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction private func buttonTapped(_ sender: Any) {
guard let fileURL = Bundle.main.url(forResource: "infomation", withExtension: "pdf") else {return}
documentController = UIDocumentInteractionController.init(url: fileURL)
documentController.delegate = self
documentController.presentPreview(animated: true)
}
}
extension ViewController: UIDocumentInteractionControllerDelegate {
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}
func documentInteractionControllerWillPresentOpenInMenu(_ controller: UIDocumentInteractionController) {
}
func documentInteractionControllerWillPresentOptionsMenu(_ controller: UIDocumentInteractionController) {
}
func documentInteractionController(_ controller: UIDocumentInteractionController, willBeginSendingToApplication application: String?) {
}
}
but none of them get called when i click on the share button, even though i have set the delegate to be my view controller.is there a way that i can do this ?
Explanation:
There isn't a way to do that without hacking it together by iterating all the sub-views and override the button's action and target.
One clean way is to create your own preview controller like shown below. If you add the QLPreviewController to UINavigationController, it will automatically create a bottom toolbar which you don't want. To work around this, you add it as a child controller of a regular UIViewController and create a custom navigation bar.
You can also use the UTI for the UIActivityItem to determine how the item can be shared. I've only implemented the preview and basic sharing capabilities, but the rest should be super easy to do, and at least it's more customizable than UIDocumentInteractionController since you have full control of everything.
Now for the code that does all of this:
//
// ViewController.swift
// CustomDocumentController
//
// Created by brandon on 2022-01-13.
//
import UIKit
import QuickLook
import MobileCoreServices
import UniformTypeIdentifiers
private class PreviewItem: NSObject, QLPreviewItem {
var previewItemURL: URL?
var previewItemTitle: String?
init(title: String, url: URL) {
super.init()
previewItemURL = url
previewItemTitle = title
}
}
class DocumentInteractionController: UIViewController {
private let url: URL
private lazy var navigationBar: UINavigationBar = {
let navigationBar = UINavigationBar()
let navigationItem = UINavigationItem(title: name ?? "Document")
navigationItem.hidesBackButton = true
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(onDone))
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(onShare)) //UIImage(systemName: "square.and.arrow.up")
navigationBar.pushItem(navigationItem, animated: false)
return navigationBar
}()
private lazy var previewController: QLPreviewController = {
let previewController = QLPreviewController()
previewController.title = name
previewController.dataSource = self
previewController.delegate = self
previewController.reloadData()
return previewController
}()
var uti: String? {
didSet {
previewController.reloadData()
}
}
var name: String? {
didSet {
previewController.title = name
navigationBar.topItem?.title = name
}
}
init(url: URL) {
self.url = url
super.init(nibName: nil, bundle: nil)
//super.init(rootViewController: self.previewController)
self.modalPresentationStyle = .fullScreen
name = (try? url.resourceValues(forKeys: [.localizedNameKey]))?.localizedName
uti = (try? url.resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
if uti == nil {
if #available(iOS 15.0, *) {
uti = UTType.url.identifier
} else {
uti = String(kUTTypeURL)
}
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
addChild(previewController)
previewController.didMove(toParent: self)
let separator = UIView()
separator.backgroundColor = .lightGray
view.addSubview(navigationBar)
view.addSubview(separator)
view.addSubview(previewController.view)
NSLayoutConstraint.activate([
navigationBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
navigationBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
separator.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
separator.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
separator.topAnchor.constraint(equalTo: navigationBar.bottomAnchor),
separator.heightAnchor.constraint(equalToConstant: 1.0 / UIScreen.main.scale),
previewController.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
previewController.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
previewController.view.topAnchor.constraint(equalTo: separator.bottomAnchor),
previewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
[navigationBar, separator, previewController.view].forEach({
$0?.translatesAutoresizingMaskIntoConstraints = false
})
navigationBar.barTintColor = previewController.view.backgroundColor
view.backgroundColor = previewController.view.backgroundColor
}
}
extension DocumentInteractionController: QLPreviewControllerDelegate, QLPreviewControllerDataSource {
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return PreviewItem(title: name ?? "Document", url: url)
}
}
extension DocumentInteractionController {
#objc
private func onDone() {
self.dismiss(animated: true, completion: nil)
}
#objc
private func onShare() {
let activityViewController = UIActivityViewController(activityItems: [url],
applicationActivities: nil)
activityViewController.excludedActivityTypes = [.assignToContact]
if UIDevice.current.userInterfaceIdiom == .pad {
activityViewController.popoverPresentationController?.sourceView = self.view
}
self.present(activityViewController, animated: true, completion: nil)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "Testing", withExtension: ".md")
let doc = DocumentInteractionController(url: url!)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.present(doc, animated: true, completion: nil)
}
}
}
Screenshots:

Picture in Picture from AVSampleBufferDisplayLayer not loading

I'm trying to support Picture in Picture for my iOS app and I need to display the content of a view, not a video. So I tried to use a library to record a view and show the video in a AVSampleBufferDisplayLayer. It works, the content of the view is displayed in the buffer display layer, but when I try to use PIP, only a loading indicator is shown. Here is my code:
import UIKit
import AVKit
class View: UIView {
override class var layerClass: AnyClass {
AVSampleBufferDisplayLayer.self
}
}
class ViewController: UIViewController, AVPictureInPictureSampleBufferPlaybackDelegate {
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, setPlaying playing: Bool) {
}
func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
.init(start: .zero, duration: self.buffers.first?.duration ?? .indefinite)
}
func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
false
}
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, didTransitionToRenderSize newRenderSize: CMVideoDimensions) {
}
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, skipByInterval skipInterval: CMTime, completion completionHandler: #escaping () -> Void) {
}
#IBOutlet weak var playerView: View!
#IBOutlet weak var textView: UITextView!
var pipController: AVPictureInPictureController?
var glimpse: Glimpse!
var isRecording = false
var buffers = [CMSampleBuffer]()
#IBAction func pip() {
pipController?.startPictureInPicture()
}
func startRecording() {
glimpse = Glimpse()
glimpse.startRecording(textView, withCallback: { url in
if let url = url {
do {
DispatchQueue.main.async {
(self.playerView.layer as! AVSampleBufferDisplayLayer).flush()
if self.pipController == nil {
self.pipController = AVPictureInPictureController(contentSource: .init(sampleBufferDisplayLayer: self.playerView.layer as! AVSampleBufferDisplayLayer, playbackDelegate: self))
self.pipController?.requiresLinearPlayback = true
}
}
let reader = try AVAssetReader(asset: AVAsset(url: url))
let output = AVAssetReaderTrackOutput(track: reader.asset.tracks.first!, outputSettings: nil)
reader.add(output)
reader.startReading()
while let buffer = output.copyNextSampleBuffer() {
self.buffers.append(buffer)
}
try FileManager.default.removeItem(at: url)
} catch {
print(error)
}
}
})
isRecording = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var i = 0
_ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
self.textView.text += "Hello World! (\(i))\n"
if self.isRecording {
self.glimpse.stop()
self.startRecording()
}
i += 1
})
let layer = playerView.layer as! AVSampleBufferDisplayLayer
layer.requestMediaDataWhenReady(on: .global()) {
if let buffer = self.buffers.first {
layer.enqueue(buffer)
self.buffers.remove(at: 0)
}
}
startRecording()
}
}
In this example, I modify the content of a UITextView every second and I record a video of it. Then I extract the CMSampleBuffers to display them in the AVSampleBufferDisplayLayer.
I attached two screenshots, the first shows how the content of the text view is successfully shown in the AVSampleBufferDisplayLayer and the second shows how nothing is displayed when PIP is enabled.
What am I doing wrong?
I have experienced the same behavior when returning incorrect time range for playback. Make sure you return .positiveInfinity for duration otherwise your layer will be covered with the loading indicator.
func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
return CMTimeRange(start: .negativeInfinity, duration: .positiveInfinity)
}
Documented here:
https://developer.apple.com/documentation/avkit/avpictureinpicturesamplebufferplaybackdelegate/3750337-pictureinpicturecontrollertimera?changes=la
I have something like this working in Secure ShellFish and it made a difference how the CMSampleBuffers was created.
I had to create the CMSampleBuffer from a CVPixelBuffer that was IOSurface compatible and I had to mark the CMSampleBuffer with kCMSampleAttachmentKey_DisplayImmediately.

How to send image from framework to sample project in iOS Swift?

I have implemented document scanner using visionKit. Initially i have faced camera dismiss issue and it fixed. Now i am trying to send image after camera dismiss from framework to sample project.
I have tried using completion handler, but it does not work.
Here is the code for framework:
public class A8Scan: NSObject, VNDocumentCameraViewControllerDelegate {
var imageNew: UIImage?
var statusImage: UIImageView?
private var clientView: UIViewController?
public init(_ viewController:UIViewController){
self.clientView = viewController
}
public func showScanner(imgData: UIImage?){
self.createTaskController(img: imgData)
print("Called Build")
}
private func createTaskController(img: UIImage?){
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self
self.clientView?.present(scannerViewController,animated:true,completion: {
self.imageNew = img
})
}
public func imageFromFile(result: #escaping (_ image: UIImage?) -> Void){
//the image
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self
self.clientView?.present(scannerViewController,animated:true,completion: nil)
if imageNew != nil {
result(imageNew)
}
else{
//callback nil so the app does not pause infinitely if
//the error != nil
result(nil)
}
}
func set(image: UIImage) {
self.statusImage?.image = image
}
public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
guard scan.pageCount >= 1 else {
controller.dismiss(animated: true)
return
}
let originalImage = scan.imageOfPage(at: 0)
let newImage = compressedImage(originalImage)
imageNew = newImage
set(image: imageNew!)
print("new image::\(newImage.size)")
controller.dismiss(animated: true, completion: nil)
// processImage(newImage)
}
public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
print(error)
controller.dismiss(animated: true)
}
public func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
controller.dismiss(animated: true)
}
func compressedImage(_ originalImage: UIImage) -> UIImage {
guard let imageData = originalImage.jpegData(compressionQuality: 1),
let reloadedImage = UIImage(data: imageData) else {
return originalImage
}
return reloadedImage
}
}
Here is the code sample project:
#IBAction func btnAction(_ sender: Any) {
// A8Scan(self).showScanner()
// A8Scan(self).showScanner(imgData: im)
// print("nn", A8Scan(self).showScanner(imgData: im))
A8Scan(self).imageFromFile { (image) in
if image != nil {
print(image!)
} else {
print("something went wrong")
}
}
// p()
}
func p (){
ScannerViewController().imageFromFile{(image: UIImage?) -> Void in
//use the image that was just retrieved
print("image data", image)
}
}
My issue is after camera dismiss from framework it does not send image from framework to sample project.
Any help much appreciated pls....
1-
Add this inside your framework
var callBack((UIImage)-())?
public func show() {
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self
self.clientView?.present(scannerViewController,animated:true,completion: nil)
}
2-
let newImage = compressedImage(originalImage)
callBack?(newImage)
3-
Then inside the vc that uses it
let vc = A8Scan(self)
vc.show()
vc.callBack = { [weak self] image in
}
As you are using a middle man (A8Scan) NSObject to present a controller. the A8Scan will get deallocated immediately after presenting the controller which you can confirm by keeping a deinit function inside A8Scan.
A workaround for this is to make your NSObject (A8Scan) as a singleton ie add
static let shared = A8Scan()
var callBack: ((_ image: UIImage?) -> Void)?
remove the existing init method and add the viewcontroller property into the imageFromFile: method, your function will look like this
public func imageFromFile(sender: UIViewController, result: #escaping (_ image: UIImage?) -> Void){
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self
self.callBack = result
sender.present(scannerViewController,animated:true,completion: nil)
}
public func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
guard scan.pageCount >= 1 else {
controller.dismiss(animated: true)
return
}
let originalImage = scan.imageOfPage(at: 0)
let newImage = compressedImage(originalImage)
imageNew = newImage
set(image: imageNew!)
callBack?(imageNew!)
controller.dismiss(animated: true, completion: nil)
}
and finally in your sample project,
#IBAction func btnAction(_ sender: Any) {
A8Scan.shared.imageFromFile(sender: self) { (image) in
if image != nil {
print(image!)
} else {
print("something went wrong")
}
}
}

Swift UIActivityViewController

Could anyone tell me how to implement "Open in Safari" in UIActivityViewController? I know this questions is a duplicate of another question posted a long time ago, and the method at that time was by using a framework that can no longer be used.
The data I am sharing is a URL. I already have a fully working ActivityVC and I only need to add that “open in safari” button.
Thank you very much.
code:
#IBAction func shareButtonPressed(_ sender: UIButton) {
let activityVC = UIActivityViewController(activityItems: [URL(string: urlStr)!], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
self.present(activityVC, animated: true, completion: nil)
}
You need to implement your own activity, please check the code below.
import UIKit
final class SafariActivity: UIActivity {
var url: URL?
override var activityImage: UIImage? {
return UIImage(named: "SafariActivity")!
}
override var activityTitle: String? {
return NSLocalizedString("Open in Safari", comment:"")
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
for item in activityItems {
if
let url = item as? URL,
UIApplication.shared.canOpenURL(url)
{
return true
}
}
return false
}
override func prepare(withActivityItems activityItems: [Any]) {
for item in activityItems {
if
let url = item as? URL,
UIApplication.shared.canOpenURL(url)
{
self.url = url
}
}
}
override func perform() {
var completed = false
if let url = self.url {
completed = UIApplication.shared.openURL(url)
}
activityDidFinish(completed)
}
}
let url = URL(string: "http://www.apple.com")!
let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: [SafariActivity()])
present(activityViewController, animated: true, completion: nil)
Updated to Swift 5.1 & iOS 13
Bonus:
ActivityType extension to use with .excludedActivityTypes.
UIImage(systemName:) to use SF Symbols plus .applyingSymbolConfiguration to take advantage of its flexibility.
To improve:
Implement completion handler on UIApplication.shared.open to handle errors (unlikely to occur).
import UIKit
extension UIActivity.ActivityType {
static let openInSafari = UIActivity.ActivityType(rawValue: "openInSafari")
}
final class SafariActivity: UIActivity {
var url: URL?
var activityCategory: UIActivity.Category = .action
override var activityType: UIActivity.ActivityType {
.openInSafari
}
override var activityTitle: String? {
"Open in Safari"
}
override var activityImage: UIImage? {
UIImage(systemName: "safari")?.applyingSymbolConfiguration(.init(scale: .large))
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
activityItems.contains { $0 is URL ? UIApplication.shared.canOpenURL($0 as! URL) : false }
}
override func prepare(withActivityItems activityItems: [Any]) {
url = activityItems.first { $0 is URL ? UIApplication.shared.canOpenURL($0 as! URL) : false } as? URL
}
override func perform() {
if let url = url {
UIApplication.shared.open(url)
}
self.activityDidFinish(true)
}
}
Try this Link if it meets your requirement
Link - https://bjartes.wordpress.com/2015/02/19/creating-custom-share-actions-in-ios-with-swift/
Code Required
class FavoriteActivity: UIActivity {
override func activityType() -> String? {
return "TestActionss.Favorite"
}
override func activityTitle() -> String? {
return "Add to Favorites"
}
override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
NSLog("%#", __FUNCTION__)
return true
}
override func prepareWithActivityItems(activityItems: [AnyObject]) {
NSLog("%#", __FUNCTION__)
}
override func activityViewController() -> UIViewController? {
NSLog("%#", __FUNCTION__)
return nil
}
override func performActivity() {
// Todo: handle action:
NSLog("%#", __FUNCTION__)
self.activityDidFinish(true)
}
override func activityImage() -> UIImage? {
return UIImage(named: "favorites_action")
}
}
Usage
#IBAction func showAvc(sender: UIButton) {
let textToShare = "Look at this awesome website!"
let myWebsite = NSURL(string: "http://www.google.com/")!
let objectsToShare = [textToShare, myWebsite]
let applicationActivities = [FavoriteActivity()]
let avc = UIActivityViewController(activityItems: objectsToShare, applicationActivities: applicationActivities)
self.presentViewController(avc, animated: true, completion: nil)
}

How to load image from camera or photo library in Swift [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
How do you take a photo with the camera or pick an image from the photo library to be able to display it in an imageView for example?
Any help on this would be appreciated.
Full update for Swift 5+ including Github Repo
First of all we want to organize everything into a dedicated class.
import MobileCoreServices
import UIKit
class CameraProvider: NSObject {
enum PhotoLibraryTypes {
case photoLibrary, savedPhotosAlbum
var casted: UIImagePickerController.SourceType {
switch self {
case .photoLibrary: return UIImagePickerController.SourceType.photoLibrary
case .savedPhotosAlbum: return UIImagePickerController.SourceType.savedPhotosAlbum
}
}
}
public typealias SourceType = UIImagePickerController.SourceType
public typealias ImagePicker = UIImagePickerController
public typealias Delegate = UINavigationControllerDelegate & UIImagePickerControllerDelegate
private let delegate: Delegate
init(delegate: Delegate) {
self.delegate = delegate
}
// MARK: - Public
public func getImagePicker(source: PhotoLibraryTypes,
canEditPhotos: Bool = true,
onlyImages: Bool = false) throws -> ImagePicker {
do {
return try getBaseController(
source: source.casted,
allowsEditing: canEditPhotos,
onlyImages: onlyImages
)
} catch {
throw error
}
}
public func getCamera(canEditPhotos: Bool = true,
onlyImages: Bool = false) throws -> ImagePicker {
do {
let picker = try getBaseController(
source: .camera,
allowsEditing: canEditPhotos,
onlyImages: onlyImages
)
if UIImagePickerController.isCameraDeviceAvailable(.rear) {
picker.cameraDevice = .rear
} else if UIImagePickerController.isCameraDeviceAvailable(.front) {
picker.cameraDevice = .front
} else {
throw "No known camera type available"
}
picker.showsCameraControls = true
return picker
} catch {
throw error
}
}
// MARK: - Private
private func getBaseController(source: SourceType,
allowsEditing: Bool,
onlyImages: Bool) throws -> ImagePicker {
guard UIImagePickerController.isSourceTypeAvailable(source) else {
throw "Requested source not available"
}
let picker = UIImagePickerController()
let imageType = kUTTypeImage as String
picker.sourceType = source
picker.allowsEditing = allowsEditing
picker.delegate = self.delegate
if onlyImages,
let mediaTypes = UIImagePickerController.availableMediaTypes(for: source),
mediaTypes.contains(imageType){
picker.mediaTypes = [imageType]
}
return picker
}
}
extension String: LocalizedError {
public var errorDescription: String? { return self }
}
Lastly we call our CameraProvider as following.
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let provider = CameraProvider(delegate: self)
do {
let picker = try provider.getImagePicker(source: .photoLibrary)
present(picker, animated: true)
} catch {
NSLog("Error: \(error.localizedDescription)")
}
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = (
info[UIImagePickerController.InfoKey.editedImage] as? UIImage ??
info[UIImagePickerController.InfoKey.originalImage] as? UIImage
)
picker.dismiss(animated: true, completion: nil)
}
}

Resources