How to pass image data of AVCaptureSession captured image to another view controller? - swift3

I made a camera app using AVFoundation's AVCaptureSession and I wanted to pass the data of the captured image to another view controller.
This is the function where the capture os being handled:
func capturePhoto() {
self.counter += 1
if let videoConnection = sessionOutput.connection(withMediaType: AVMediaTypeVideo) {
videoConnection.videoOrientation = .landscapeRight
sessionOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (buffer, error) in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
let data = NSData(data: imageData!)
// append the data to a global variable
DispatchQueue.main.async {
self.imageData?.append(data)
}
let image = UIImage(data: imageData!)!
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
})
}
if self.counter == self.count {
self.timer?.invalidate()
self.timer = nil
self.counter = 0
self.shutterTimer.isHidden = true
self.shutterTimer.layer.removeAllAnimations()
// if the condition is met, then go to another vc with the image data
setupFrameAndSave()
}
}
this is the function that handles the segue to another view controller with the image data:
func setupFrameAndSave() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "saveVC") as! SaveVC
controller.imageData = self.imageData
self.present(controller, animated: true, completion: nil)
}
Now, the problem is that the data that is being passed prints nil and placing the appending data to array inside DispatchQueue.main.async didn't do anything.

Related

How to set an image in imageview swift 3?

So I have an image view titled cashOrCredit and have am trying to set it's image programatically but somehow not able to.
First I set the image like this
cell.cashOrCredit.image = UIImage(named: "cash1.png")
and I get an error saying a separator of "," is needed.
Then I tried it this way
var cashImage: UIImage?
cashImage = "cash1.png"
cell.cashOrCredit.image = cashImage
But I get a THREAD 1 EXC BAD INSTRUCTION error.
I can't seem to understand what is going wrong ?
Here is the error
Updated for Swift 3:
use below simple code, to set the image to UIImageView;
class YourViewControllerName: UIViewController {
var mYourImageViewOutlet: UIImageView?
func addImageToUIImageView{
var yourImage: UIImage = UIImage(named: "Birthday_logo")!
mYourImageViewOutlet.image = yourImage
} // call this function where you want to set image.
}
Note: "Birthday_logo" type of image must be present in your Assets.xcassets of your project.
I attached the screenshot if you want any help please refer it.
****// used anywhere you want to add an image to UIImageView. [Here I used one function & in that function, I write a code to set image to UIImageView]****
Enjoy..!
Try this:
cell.cashOrCredit.image = UIImage(named: "cash1")
and check "cash1.png" image is available in Assets.xcassets or not.
If you get solution, then give upvote to my answer.
Delete ".png":
cell.cashOrCredit.image = UIImage(named: "cash1")
You can also set it all programmatically:
let cellImage = UIImageView(frame: CGRect(x: X, y: Y, width: WIDTH, height: HEIGHT))
cellImage.image = UIImage(named: "cash1")
cell.addSubview(cellImage)
Take Outlet of ImageView
#IBOutlet weak var imgProfile: UIImageView!
Go through the following code which contains will be helpful you to pick image or capture image from the camera.
func choosePicker() {
let alertController = UIAlertController(title: "Select Option", message: nil, preferredStyle: (IS_IPAD ? UIAlertControllerStyle.alert : UIAlertControllerStyle.actionSheet))
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { action -> Void in
})
let gallery = UIAlertAction(title: "From Gallery", style: UIAlertActionStyle.default
, handler: { action -> Void in
self.openPicker(isCamera: false)
})
let camera = UIAlertAction(title: "Take Photo", style: UIAlertActionStyle.default
, handler: { action -> Void in
self.openPicker(isCamera: true)
})
alertController.addAction(gallery)
alertController.addAction(camera)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
func openPicker(isCamera : Bool) {
let picker:UIImagePickerController?=UIImagePickerController()
if isCamera {
picker!.sourceType = UIImagePickerControllerSourceType.camera
} else {
picker!.sourceType = UIImagePickerControllerSourceType.photoLibrary
picker!.allowsEditing = true
}
picker?.delegate = self
if UIDevice.current.userInterfaceIdiom == .phone {
self.present(picker!, animated: true, completion: nil)
}
else {
picker!.modalPresentationStyle = .popover
present(picker!, animated: true, completion: nil)//4
picker!.popoverPresentationController?.sourceView = imgProfile
picker!.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.up
}
}
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
self.imgProfile.image = image
}
picker.dismiss(animated: true, completion: nil);
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
Call choosePicker method wherever you want to call.
Check if cashOrCredit is uiimageview.
Secondly,
cashImage = UIImage(named: "cash1.png")
If that doesnot work, try
cell?. cashOrCredit.image
check if cell is nil?
In the context of Swift code, EXC_BAD_INSTRUCTION usually means you’ve hit a compiler trap, that is, an undefined instruction inserted into the code by the compiler because of a bug detected at runtime. The most common cause of these are:
failure to unwrap an optional — This can be a forced unwrap (!) or an implicit unwrap (accessing an implicitly unwrapped optional that’s nil).
array out of bounds
a failed forced cast (as!), either because the value was a nil optional or because the value was of the wrong type

Passing data from vc1 to vc2 programmatically using present or push?

This is my code in VC1
I have this var user = User() in VC1 that has all the data.
func handleMessageView() {
let layout = UICollectionViewFlowLayout()
let messageViewController = MessageViewController(collectionViewLayout: layout)
messageViewController.user = user
let messageNavController = UINavigationController(rootViewController: messageViewController)
self.present(messageNavController, animated: true, completion: nil)
}
This is called by a UIBarbutton.
in VC2 I just have a recieving var. var user = User()
This var is returning a nil, Im not using storyboard nor xib. This is all programmatic.

Recording video to specific album

I am creating an album in the users photo library, now I want to save a video there. I am saving the video to a file using:
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let filePath = documentsURL.URLByAppendingPathComponent("video")
Now I want to take the video, and save it to an album. I've found lots on saving to the camera roll, but nothing on saving to an album. Can it be done, and if so, how?
Assuming you have a PHAssetCollection specifying the album, you can use this PHAssetCollection extension:
extension PHAssetCollection {
private func isCameraRollAlbum() -> Bool
{
let query = PHAssetCollection.fetchAssetCollections(with: .smartAlbum,
subtype: .smartAlbumUserLibrary,
options: nil)
let result: PHAssetCollection? = query.firstObject
return self == result
}
func save(videoURL: URL, completion: #escaping (URL?, String?) -> ()) {
let isCameraRoll = isCameraRollAlbum()
DispatchQueue.global(qos: .userInteractive).asyncAfter(deadline: .now()) {
PHPhotoLibrary.shared().performChanges({
if let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL) {
if isCameraRoll == false, let placeholder = assetRequest.placeholderForCreatedAsset {
let albumChangeRequest = PHAssetCollectionChangeRequest(for: self)
albumChangeRequest?.addAssets([placeholder] as NSArray)
}
}
}, completionHandler: { (success, error) in
if success == false {
completion(nil, error?.localizedDescription)
}
else {
completion(videoURL, nil)
}
})
}
}
}
Remarks:
Method 'isCameraRollAlbum' was defined because it was found that the use of placeholders for the whole photo album doesn't work, and you only need to use
PHAssetChangeRequest.creationRequestForAssetFromVideo
to save a video to the whole photo library.
Using a background thread is not necessary.
Example usage, it is assumed a video named 'Video.mov' is in the Documents directory of the app. This will save it to the 'Camera Roll' album but a PHAssetCollection for any album can be specified:
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let videoURL = docsurl.appendingPathComponent("Video.mov")
let fetchResult = PHAssetCollection.fetchAssetCollections(with:.smartAlbum,subtype:.smartAlbumUserLibrary,options: nil)
if let allMediaAlbum = fetchResult.firstObject {
allMediaAlbum.save(videoURL: videoURL) { (url, message) in
print("message = \(String(describing: message))")
}
}
For example, you can use this extension to obtain the PHAssetCollection for an album with a given name 'title':
class func getAlbum(title: String, completionHandler: #escaping (PHAssetCollection?) -> ()) {
DispatchQueue.global(qos: .userInteractive).asyncAfter(deadline: .now()) {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", title)
let collections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let album = collections.firstObject {
completionHandler(album)
} else {
completionHandler(nil)
}
}
}
Example usage, saving video 'Video.mov' to album named 'My Umbrella':
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let albumName = "My Umbrella"
let videoURL = docsurl.appendingPathComponent("Video.mov")
PHAssetCollection.getAlbum(title: albumName) { (album) in
if let album = album {
album.save(videoURL: videoURL, completion: { (url, error) in
if let url = url {
print("Video '\(url.lastPathComponent) saved to '\(albumName)'")
}
else {
print("Error: \(String(describing: error))")
}
})
}
}
(Keep in mind that the photos library can have multiple albums by the same name.)

api youtube in swift 3 error 403

I am trying to use youtube api in ios swift, and following this tutorial
http://www.appcoda.com/youtube-api-ios-tutorial/
HTTP Status Code = 403
Error while loading channel details: nil
I'm using swift 3
var urlString = "https://www.googleapis.com/youtube/v3/search?part=snippet&q=\(textField.text)&type=\(type)&key=\(apiKey)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Get the results.
performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
// Convert the JSON data to a dictionary object.
do {
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<String, AnyObject>
// Get all search result items ("items" array).
let items: Array<Dictionary<String, AnyObject>> = resultsDict["items"] as! Array<Dictionary<String, AnyObject>>
// Loop through all search results and keep just the necessary data.
for i in 0 ..< items.count {
let snippetDict = items[i]["snippet"] as! Dictionary<String, AnyObject>
// Gather the proper data depending on whether we're searching for channels or for videos.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
// Keep the channel ID.
self.desiredChannelsArray.append(snippetDict["channelId"] as! String)
}
else {
// Create a new dictionary to store the video details.
var videoDetailsDict = Dictionary<String, AnyObject>()
videoDetailsDict["title"] = snippetDict["title"]
videoDetailsDict["thumbnail"] = ((snippetDict["thumbnails"] as! Dictionary<String, AnyObject>)["default"] as! Dictionary<String, AnyObject>)["url"]
videoDetailsDict["videoID"] = (items[i]["id"] as! Dictionary<String, AnyObject>)["videoId"]
// Append the desiredPlaylistItemDataDict dictionary to the videos array.
self.videosArray.append(videoDetailsDict)
// Reload the tableview.
self.tblVideos.reloadData()
}
}
} catch {
print(error)
}
// Call the getChannelDetails(…) function to fetch the channels.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
self.getChannelDetails(true)
}
}
else {
print("HTTP Status Code = \(HTTPStatusCode)")
print("Error while loading channel videos: \(error)")
}
// Hide the activity indicator.
self.viewWait.isHidden = true
})
return true
}
// MARK: Custom method implementation
func performGetRequest(_ targetURL: URL!, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int, _ error: NSError?) -> Void) {
// let request = NSMutableURLRequest(url: targetURL)
// request.httpMethod = "GET"
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
/* let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void)*/
/* let task = session.dataTask(with: request, completionHandler: ({ (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data as Data?, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void))*/
let task = session.dataTask(with: request) { data, response, error in DispatchQueue.main.async { completion(data, (response as! HTTPURLResponse).statusCode, error as? NSError) } }
task.resume()
}
First of all the JSON dictionary representation in Swift 3 is [String:Any] (aka Dictionary<String,Any>)
Second of all in Swift 3 all parameter labels in closures have been removed
func performGetRequest(_ targetURL: URL, completion: #escaping (Data?, Int, NSError?) -> Void) {
Do not use implicit unwrapped optionals for method parameter types. Either use regular optional (?) or non-optional.
Error 403 means Forbidden Access. Make sure you have the correct apiKey from google/youtube developer.
I also used the appcoda youtube api tutorial (which is in Swift 2 I think) and this is a working version of mine for swift 3.
func getVideosForChannelAtIndex() {
let urlString = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=\(playlistID)&maxResults=\(maxResults)&key=\(apiKey)"
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Fetch the playlist from Google.
performGetRequest(targetURL!) { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
do {
self.videos = []
// Convert the JSON data into a dictionary.
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<AnyHashable, Any>
// Get all playlist items ("items" array).
let items:Array<Dictionary<AnyHashable, Any>> = resultsDict["items"] as! Array<Dictionary<AnyHashable, Any>>
// Use a loop to go through all video items.
// for var i=0; i<items.count; ++i
for i in 0 ..< items.count {
let playlistSnippetDict = (items[i] as Dictionary<AnyHashable, Any>)["snippet"] as! Dictionary<AnyHashable, Any>
let video = Video()
video.title = playlistSnippetDict["title"] as? String
// video.thumbnail =
video.videoId = (playlistSnippetDict["resourceId"] as? Dictionary<AnyHashable, Any>)?["videoId"] as? String
guard let thumbnail = ((playlistSnippetDict["thumbnails"] as? Dictionary<AnyHashable, Any>)?["high"] as? Dictionary<AnyHashable, Any>)?["url"] as? String else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
guard let url:URL? = URL(string: thumbnail), let data:Data? = try? Data(contentsOf: url!) else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
if let dataImage = data {
video.thumbnail = UIImage(data: dataImage)
} else {
video.thumbnail = UIImage(named: "Icon1024x1024")
}
self.videos.append(video)
// Reload the tableview.
self.tblVideos.reloadData()
}
} catch {
print("json error: \(error)")
}
} else {
print("")
print("HTTP Status Code = \(HTTPStatusCode)")
print("")
//Show alertDialog here with Error
print("Error while loading videos: \(error?.localizedDescription)")
let alert = UIAlertView(title: "Oops!", message: error?.localizedDescription, delegate: self, cancelButtonTitle: "OK")
alert.show()
}
// Hide the activity indicator.
self.viewWait.isHidden = true
}
}
This is for the performGetRequest
func performGetRequest(_ targetURL: URL, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int?, _ error: Error?) -> Void) {
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
completion(data, (response as? HTTPURLResponse)?.statusCode, error)
})
}
task.resume()
}

Resume Data from URLSessionDownloadTask Always nil

i have an app which i need to download the file from the internet when i downloading the file it's work good but my problem is when i pressed pause button to pause the downloading for one minute or more i get nil from resume Data
the following my code :
#IBAction func startDownloading(_ sender: UIButton)
{
isDownload = true
sessionConfig = URLSessionConfiguration.default
let operationQueue = OperationQueue.main
session = URLSession.init(configuration: sessionConfig, delegate: self, delegateQueue: operationQueue)
let url = URL(string: "www.example.com")
downloadTask = session.downloadTask(with: url!)
downloadTask.resume()
}
#IBAction func pause(_ sender: UIButton)
{
if downloadTask != nil && isDownload
{
self.downloadTask!.cancel(byProducingResumeData: { (resumeData) in
// here is the nil from the resume data
})
isDownload = false
downloadTask = nil
pasueBtnOutlet.setTitle("Resume", for: .normal)
}
if !isDownload && downloadData != nil
{
downloadTask = session.downloadTask(withResumeData: downloadData as Data)
downloadTask.resume()
isDownload = true
downloadData = nil
pasueBtnOutlet.setTitle("Pause", for: .normal)
}
}
please can help me
thanks for all
Your code seems to be correct, you just need to init the downloadData with resumeData in closure
Make a property of downloadData
var downloadData:Data!
and then in your pause button action where you cancel the task, set the downloadData with resumeData
self.downloadTask!.cancel(byProducingResumeData: { (resumeData) in
// here is the nil from the resume data
// You have to set download data with resume data
self.downloadData = resumeData
})
In order to check the progress and completion, implement these URLSessionDownloadDelegate delegates
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
print(Int(progress * 100))
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("Downloading done")
}
NOTE:- Try a valid downloadable url. For example
http://www.star.uclan.ac.uk/news_and_events/news/2010020901/sdo_resolution_comparison.png
Its http, make sure to set Transport Security in Info.plist