Swift video file captured doesn't exists in another viewcontroller - ios

Captured a video in one viewcontroller and trying to preview it in another and upload it. Everything works fine till when I try the uploading where it gives me file doesn't exists
VideoRecorderViewController.swift
func finishRecording(outputFileURL: URL!) {
DispatchQueue.main.async { [unowned self] in
let path = outputFileURL.path
if FileManager.default.fileExists(atPath: path) {
//it comes here
}
let vc: VideoViewController? = self.storyboard?.instantiateViewController(withIdentifier: "VideoVC") as? VideoViewController
if let validVC: VideoViewController = vc {
validVC.videoURL = outputFileURL as NSURL?
self.navigationController?.pushViewController(validVC, animated: true)
}
}
}
VideoViewController.swift
var videoURL = NSURL(string: "")
#IBAction func btnSave(_ sender: Any) {
print (self.videoURL!)
// returns file:///private/var/mobile/Containers/Data/Application/228FAD74-B7C3-4838-8114-ED16D995FF9A/tmp/3B256E17-9875-4610-B8B3-348FBFAEC409.mov
print (self.videoURL!.path!)
//returns /private/var/mobile/Containers/Data/Application/228FAD74-B7C3-4838-8114-ED16D995FF9A/tmp/3B256E17-9875-4610-B8B3-348FBFAEC409.mov
let path = self.videoURL!.path!
if FileManager.default.fileExists(atPath: path) {
// "never comes"
}
}

Related

Playing Vimeo video using HCVimeoVideoExtractor, can't get video URL with specific quality

I'm using this lib https://github.com/superm0/HCVimeoVideoExtractor to play vimeo url. It works fine but changing the quality doesn't return videoURL for some videos. I'm talking about this line
if let videoURL = vid.videoURL[.Quality1080p]
I'm not able to understand why it doesn't return videoURL for a video when I pass Quality1080p?
How to fix it? Is there something wrong with my videos? Do I need to convert all of videos to same quality and then upload on Vimeo?
Following is my code:
import UIKit
import HCVimeoVideoExtractor
import AVKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playClicked(_ sender: UIButton) {
guard let url = URL(string: "https://vimeo.com/1234567") else {
print("Error url nill")
return
}
HCVimeoVideoExtractor.fetchVideoURLFrom(url: url, completion: { ( video:HCVimeoVideo?, error:Error?) -> Void in
if let err = error {
print("Error = \(err.localizedDescription)")
return
}
guard let vid = video else {
print("Invalid video object")
return
}
print("Title = \(vid.title), url = \(vid.videoURL), thumbnail = \(vid.thumbnailURL)")
if let videoURL = vid.videoURL[.Quality1080p] {
let player = AVPlayer(url: videoURL)
DispatchQueue.main.async {
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true) {
player.play()
}
}
} else {
print("Error: videoURL not found")
}
})
}
}
This will helps you i think. Add this to your code
This is the count of your video last numbers
videoArr = self.arrFilterItems[indexPath.row].link
last9 = String(videoArr.suffix(9))
var last9 = String()
here link = https://vimeo.com/(123456789) == 9 or (123456) == 6

AVAudioengine play / loop audio , multiple buttons

I have this button to play and loop a wav. But what if I have a second button with another loop? I want this second loop to start playing once pressed, however, the first loop must finish his 'round'. And vice versa (play and loop the second loop, press button first loop and it takes over)
#IBAction func playButtonTapped(_ sender: Any) {
guard let filePath: String = Bundle.main.path(forResource: "25loop110", ofType: "wav") else{ return }
print("\(filePath)")
let fileURL: URL = URL(fileURLWithPath: filePath)
guard
let audioFile = try? AVAudioFile(forReading: fileURL) else{ return }
let audioFormat = audioFile.processingFormat
let audioFrameCount = UInt32(audioFile.length)
guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) else{ return }
do{
try audioFile.read(into: audioFileBuffer)
timeShift.rate = adjustedBpm/bpm
playerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)
} catch{
print("over")
}
try? audioEngine.start()
playerNode.play()
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:.loops,completionHandler: nil)
}
You can handle this behavior by using the completionHandler parameter of .scheduleBuffer.
For example, you could do something like this:
var nextAudioFilePath: String
var isPlaying: Bool = false
#IBAction func playLoopA() {
guard let path = Bundle.main.path(forResource: "audioFileA", ofType: "wav") else { return }
nextAudioFilePath = path
guard !isPlaying else { return }
play()
}
#IBAction func playLoopB() {
guard let path = Bundle.main.path(forResource: "audioFileB", ofType: "wav") else { return }
nextAudioFilePath = path
guard !isPlaying else { return }
play()
}
private func play() {
let fileURL = URL(fileURLWithPath: nextAudioFilePath)
...
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options: [], completionHandler: { [weak self] in
self?.play()
})
}
I also found this solution:
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:[.interruptsAtLoop, .loops],completionHandler: nil)

MFMailComposeViewController taking ages to send email

I'm building an app in which I need to attach and send multiple photos in an email. To accomplish this I save the photos to disk in the camera VC and access them in the viewDidLoad() of the email VC. I store them as .pngData() in a array and attach them in the MFMailComposeViewController using this code:
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients([UserDefaults.standard.string(forKey: "Email")!])
mailComposerVC.setSubject("Заявление")
mailComposerVC.setMessageBody("\(ProtocolText.text!)", isHTML: false)
// unpacking images from array and attaching them to Email
var dataName = 0
for data in imageData {
dataName += 1
mailComposerVC.addAttachmentData(data, mimeType: "image/png", fileName: "\(dataName).png")
}
return mailComposerVC
}
These are my "save" and "get" methods:
func loadImage(fileName: String) -> UIImage? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
let image = UIImage(contentsOfFile: imageUrl.path)
return image
}
return nil
}
// Used in CameraViewController
func saveImage(imageName: String, image: UIImage) {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileName = imageName
let fileURL = documentsDirectory.appendingPathComponent(fileName)
guard let data = image.jpegData(compressionQuality: 1) else { return }
//Checks if file exists, removes it if so.
if FileManager.default.fileExists(atPath: fileURL.path) {
do {
try FileManager.default.removeItem(atPath: fileURL.path)
print("Removed old image")
} catch let removeError {
print("couldn't remove file at path", removeError)
}
}
do {
try data.write(to: fileURL)
} catch let error {
print("error saving file with error", error)
}
}
For some reason the images attach but the email takes at least 15 seconds to send. The "send" button just gets stuck. I don't know why. Please help.
It was a problem with the weight of the image. One image used to weigh 6848.7939453125 KB. Since I had multiple images it took a lot of time to process them. Compressing them using the image.jpegData(compressionQuality: CGFloat)!) method solved all problems. Thank you Mark Thormann for suggesting the fix!

how to share QR created image swift 4

I am creating QR code in swift and assigning it to an imageView
when I try to share that image with generated code, it does not shares that image,
func createCode()
{
let text = email
let data = text.data(using: .ascii, allowLossyConversion: false)
fillter = CIFilter(name: "CIQRCodeGenerator")
fillter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 5.0, y: 5.0)
CreatedImage = UIImage(ciImage: (fillter.outputImage?.transformed(by: transform))!)
imageCode.image = CreatedImage as UIImage
}
and this is share button
#IBAction func shareButtonPressed(_ sender: Any)
{
let activityItem: [UIImage] = [imageCode.image!]
let activity = UIActivityViewController(activityItems: activityItem as [UIImage], applicationActivities: [])
activity.popoverPresentationController?.sourceView = self.view
self.present(activity, animated: true, completion: nil)
}
it shows like it has nothing to share, it does not pick any bit of image
Have you created a variable to store the image somewhere e.g.
var generatedImage: UIImage?
Assuming then, that I have read your question correctly, in your creation function you can cast the image at the end of the function e.g:
generatedImage = imageCode.image
Then in your share function you could say:
guard let validQR = generatedImage else { return }
let activityItem: [UIImage] = [validQR]
let activity = UIActivityViewController(activityItems: activityItem as [UIImage], applicationActivities: [])
activity.popoverPresentationController?.sourceView = self.view
self.present(activity, animated: true, completion: nil)
I tested with an image from my Bundle e.g:
generatedImage = UIImage(named: "SCNPyramid")
And I was able to share the image :)
after searching all..
I cam I to know that make a programmatically screen shot of desired view, that is sent..
I have been having the same problem and solved it by first saving the generated qr code image to a file and then sharing the file url.
private func shareQRCode() {
guard let qrcode = self.qrCodeImage,
let data = qrcode.pngData(),
let url = self.saveInCache(data: data, fileName: "QRCode.png") else { return }
// set up activity view controller
let imageToShare = [url]
let activityViewController = UIActivityViewController(activityItems: imageToShare, applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
// work around to prevent dismissing current view after saving image
let tempController = TransparentViewController()
tempController.modalPresentationStyle = .overFullScreen
activityViewController.completionWithItemsHandler = { [weak tempController] _, _, _, _ in
if let presentingViewController = tempController?.presentingViewController {
presentingViewController.dismiss(animated: false, completion: nil)
} else {
tempController?.dismiss(animated: false, completion: nil)
}
}
present(tempController, animated: true) { [weak tempController] in
tempController?.present(activityViewController, animated: true, completion: nil)
}
}
Here is the code for saveInCache function:
private func saveInCache(data: Data, fileName: String) -> URL? {
let paths = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
let path = paths[0]
let fileUrl = path.appendingPathComponent(fileName)
let fileManager = FileManager.default
if self.pathExists(fileUrl) {
do {
try fileManager.removeItem(at: fileUrl)
} catch { return fileUrl }
}
guard fileManager.createFile(atPath: fileUrl.path, contents: data, attributes: nil) else {
return nil
}
return fileUrl
}
private func pathExists(_ path: URL) -> Bool {
let fileManager = FileManager.default
var isDir: ObjCBool = false
if fileManager.fileExists(atPath: path.path, isDirectory: &isDir) {
if isDir.boolValue {
// file exists and is a directory
return true
} else {
// file exists and is not a directory
return true
}
} else {
// file does not exist
return false
}
}
And here a simple Transparent View Controller for ActivityViewController work around:
final class TransparentViewController: UIViewController {
override func viewDidLoad() {
self.view.backgroundColor = .clear
}
}

presentOpenInMenu shows all options on trying to share image in instagram

I am trying to share an image from my application to Instagram. I have followed all the steps mentioned here.
https://www.instagram.com/developer/mobile-sharing/iphone-hooks/
Here is my code
class ViewController: UIViewController {
lazy private var documentInteractionController = UIDocumentInteractionController()
func shareImageOnInstagram()
{
let image = UIImage(named: "sample")
let instagramURL = NSURL(string: "instagram://app")
if UIApplication.shared.canOpenURL(instagramURL! as URL) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let saveImagePath = (documentsPath as NSString).appendingPathComponent("Image.igo")
let imageData = UIImagePNGRepresentation(image!)
do {
try imageData?.write(to: URL.init(fileURLWithPath: saveImagePath), options: NSData.WritingOptions(rawValue: 0))
} catch {
print("Instagram sharing error")
}
documentInteractionController.url = URL.init(fileURLWithPath: saveImagePath)
documentInteractionController.uti = "com.instagram.exclusivegram"
if !self.documentInteractionController.presentOpenInMenu(from: CGRect.zero, in: self.view, animated: true) {
print("Instagram not found")
}
}
else {
print("Instagram not found")
}
}
#IBAction func onShowInstagramClicked(_ sender: Any)
{
self.shareImageOnInstagram()
}
}
In iOS 11.1 whenever onShowInstagramClicked is called, it shows all other applications including instagram.
Same piece of code works perfectly fine on iOS 10.3.2 and shows instagram (and Notes)
Is there any extra thing necessary for iOS 11 ?

Resources