How can I download an mp4 straight to my hard drive in Swift? - xcode

I'm using this code to download an mp4 file:
func downloadImageFile() {
let myURLstring = getImageURLCM()
let myFilePathString = "/Users/jack/Desktop/Comics/"+getTitle()+".mp4"
let url = NSURL(string: myURLstring)
let dataFromURL = NSData(contentsOfURL: url!)
let fileManager = NSFileManager.defaultManager()
fileManager.createFileAtPath(myFilePathString, contents: dataFromURL, attributes: nil)
}
But I've noticed that the file actually gets loaded up into my RAM first, before the NSFileManager saves it to my hard drive (based on the Xcode debug session). That's tolerable for smaller files, but most of the files I want to download with this will be at least 1GB.
My main question is: how to make this more RAM friendly?
I've also noticed that I get the spinning wheel of death until the download is finished, so if advice on fixing that would be appreciated as well.

You would be better to go with the system managed download in NSURLSession, specifically NSURLDownloadTask. This way you don't have to worry about memory management of large downloads. From NSURLSession swift file
/*
* download task convenience methods. When a download successfully
* completes, the NSURL will point to a file that must be read or
* copied during the invocation of the completion routine. The file
* will be removed automatically.
*/
func downloadTaskWithURL(url: NSURL, completionHandler: (NSURL?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDownloadTask?
Example of Use below - copy and paste into new Swift Playground:
import UIKit
import XCPlayground
func downloadFile(filePath: String) {
let url = NSURL(string: filePath)
if let unwrappedURL = url {
let downloadTask = NSURLSession.sharedSession().downloadTaskWithURL(unwrappedURL) { (urlToCompletedFile, reponse, error) -> Void in
// unwrap error if present
if let unwrappedError = error {
print(unwrappedError)
}
else {
if let unwrappedURLToCachedCompletedFile = urlToCompletedFile {
print(unwrappedURLToCachedCompletedFile)
// Copy this file to your destinationURL with
//NSFileManager.defaultManager().copyItemAtURL
}
}
}
downloadTask?.resume()
}
}
downloadFile("http://devstreaming.apple.com/videos/wwdc/2015/711y6zlz0ll/711/711_networking_with_nsurlsession.pdf?dl=1")
XCPSetExecutionShouldContinueIndefinitely()
Simple Example on github here - https://github.com/serendipityapps/NSURLSessionDownloadTaskExample

dataFromURL.writeToFile(myFilePathString, atomically: true)
This is the snippet I use, it writes the loaded data into the file at the given path.

Related

How do I read a text-file's content from it's shared Dropbox link in Swift 4.2 (without downloading)?

I'm having a hard time figuring out how to output a simple text-file's content from it's shared Dropbox link (without downloading) through Swift 4.2.
For Example:
let url = URL(string: "https://www.dropbox.com/s/rokwv82h54ogwy1/test.txt?dl=0")!
// the dropbox link above is a shared link so anyone can view it
do {
let content = try String(contentsOf: url)
print("File Content: \(content)")
} catch let error as NSError {
print("\(error)")
}
When I run this code I get this error:
Error Domain=NSCocoaErrorDomain Code=260 "The file “test.txt” couldn’t be opened because there is no such file."(there's more to the error but it's quite big)
Can anyone help me out please? Thanks.
There's more to the error but it's quite big
Do not strip error messages. If you don't know to fix this issue, you probably don't know what to strip to keep it valuable.
How to fix your problem
Select target
Switch to Signing & Capabilities tab
App Sandbox - Network - enable Outgoing Connections (Client)
Change the URL (dl=0) to (dl=1)
0 = display web page with a preview and download link
1 = do not display any web page, just serve the file
let url = URL(string: "https://www.dropbox.com/s/rokwv82h54ogwy1/test.txt?dl=1")!
// Change dl=0 to dl=1 ^
do {
let content = try String(contentsOf: url)
print("File Content: \(content)")
} catch let error as NSError {
print("\(error)")
}
Run again and you'll get:
File Content:
This is a test. If you can read this, you have passed! :)
Do not use String(contentsOf: url), because it's not async and it will block the main thread (UI).
Asynchronous example - imagine you have a view controller with one text field (label) and you'd like to display the file content there:
import Cocoa
class ViewController: NSViewController {
#IBOutlet var textField: NSTextField!
override func viewWillAppear() {
super.viewWillAppear()
textField.stringValue = "Loading ..."
loadRemoteFile()
}
func loadRemoteFile() {
let url = URL(string: "https://www.dropbox.com/s/rokwv82h54ogwy1/test.txt?dl=1")!
let task = URLSession.shared.dataTask(with: url) { data, _, error in
// Following code is not called on the main thread. If we'd like to
// modify UI elements, we have to dispatch our code on the main thread.
// Hence the DispatchQueue.main.async {}.
if let error = error {
print("Failed with error: \(error)")
DispatchQueue.main.async { self.textField.stringValue = "Failed" }
return
}
guard let data = data,
let content = String(data: data, encoding: .utf8) else {
print("Failed to decode data as an UTF-8 string")
DispatchQueue.main.async { self.textField.stringValue = "Failed" }
return
}
print("Content: \(content)")
DispatchQueue.main.async { self.textField.stringValue = content }
}
// At this point, we have a task which will download the file, but the task
// is not running. Every task is initially suspended.
task.resume() // Start the background task
// At this point, your program normally continues, because the download
// is executed in the background (not on the main thread).
}
}

Trying to verify persistence on data of os x application

I have created an Xcode 11 OS X targeted program to persist with CoreData. I want to verify the contents of written records on the disk. I have read that persistence is implemented by Xcode using SQLite. I have so far been unable to find such a file.
I apologize in advance for not knowing how to use code fences. I've included a line in the code which I had hoped would provide the path to any saved files but after searching the folder I find no ".db" files
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = NSApplication.shared.delegate as! AppDelegate // Do any additional setup after loading the view.
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Plants", in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
print(paths[0])
newUser.setValue("James B", forKey: "name")
newUser.setValue("Spring", forKey: "fertilizeSeason")
do {
try context.save()
} catch {
print("Failed saving")
}
}
Hoped to find .db file at the returned path.

get NSURLSession download progress in all view controllers

So i have a FirstViewController where i download a video with the progress view and progress is working fine using this code
func startDownloading() {
let download = Downloads(url: videoUrl!.absoluteString!)
download.downloadTask = self.downloadsSession.downloadTaskWithURL(videoUrl!)
download.downloadTask!.resume()
download.isDownloading = true
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
// 1
print("URLSession Completed for url \(downloadTask.originalRequest?.URL?.absoluteString)")
if let originalURL = downloadTask.originalRequest?.URL?.absoluteString,
destinationURL = localFilePathForUrl(originalURL) {
let fileManager = NSFileManager.defaultManager()
do {
try fileManager.removeItemAtURL(destinationURL)
} catch {
// Non-fatal: file probably doesn't exist
}
do {
try! fileManager.copyItemAtURL(location, toURL: destinationURL)
} catch let error as NSError {
print("Could not copy file to disk: \(error.localizedDescription)")
}
}
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
print("URLSession inProgress \(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite))")
if let downloadUrl = downloadTask.originalRequest?.URL?.absoluteString,
let download = activeDownloads[downloadUrl] {
//THIS SETS THE PROGRESS
download.progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)
self.downloadView.state = .Downloading
self.downloadView.setProgress(Double(totalSize)!, animated: true)
}
}
now this code updates FirstViewControllers downloadView.progress correctly but what i want is when i go to SecondViewController i should get the progress of this ongoing download in SecondVC too without starting the download progress again (i know downloading again would be very dumb).
The best way is to separate your network request manager code from the view controller:
Create a separate class to manage the requests, and move your delegate code there.
In the didWriteData method, use NSNotificationCenter to broadcast the notification to any interested view class or make your first view controller notify the second one if it exists.
In each of your view controller classes, register for the notification and when you receive it, update the status accordingly.

How come I can't successfully load an NSImage from it's full path? Swift 2

I'm trying to load an image from an absolute path into an NSImage and even though the same full path works in other scenarios when I'm using it in this context, the variable just ends up being nil. I've tried using both the file path and an NSURL to achieve it.
//: Playground - noun: a place where people can play
import Cocoa
import AppKit
print ("Starting")
/**
Attempt to do via NSURL
**/
// The workspace
var workspace = NSWorkspace.sharedWorkspace()
// Main screen
var screen = NSScreen.mainScreen()
let filemgr = NSFileManager.defaultManager()
print(filemgr.currentDirectoryPath)
let filePath1 = "/Users/daniel/Google Drive/elementarian wallpapers/Bicycle by midnighttokerkate.png"
let filePath2 = "/Users/daniel/Google Drive/elementarian wallpapers/Buildings Foggy Sky by solutionall.png"
let file1 = NSURL(fileURLWithPath: filePath1, isDirectory: false)
let file2 = NSURL(fileURLWithPath: filePath2, isDirectory: false)
do {
try workspace.setDesktopImageURL(file2, forScreen: screen!, options: [:])
print("Successfully set background from NSURL")
} catch {
print("Failed to set")
}
print("Attempting to set from NSData...")
/**
Attempt to do via NSData
**/
// Load image from URL first
if filemgr.fileExistsAtPath(filePath2) {
print("File exists")
var image = NSImage(contentsOfURL: file2)
if image != nil {
print ("Not nil")
} else {
print ("Nil")
}
} else {
print("File not found")
}
My final goal is to load the image into an NSData object so I can run a transform on it and then set the manipulated in memory image as the desktop background.
As per Droppy's comment, this was due to the Swift Playground running in a sandbox and not allowing access to files outside of it's workplace. I've moved the images I need into the playground itself to test and it now works as expected. Details on how to do this can be found here.

Simple Swift file download with URL

So I have the URL as string (in this case a JPG but would like a general procedure for any file type if possible) and I have the file path as string where I want to save the file.
What would be the fastest way to get this implemented?
Please keep in mind this is for OSX command line application. I tried few sample codes found here, mostly using UIImage but I get error:"Use of unresolved identifier", adding "import UIKit" gets me error:"No such Module". Please help!
import Foundation
let myURLstring = "http://www.safety.vanderbilt.edu/images/staff/Bob-Wheaton.jpg"
let myFilePathString = "/Volumes/HD/Staff Pictures/Bob-VEHS.jpg"
---> ABOVE IS THE ORIGINAL QUESTION <---
---> BELOW IS NEW IMPROVED CODE: WORKING <---
import Foundation
let myURLstring = "http://www.safety.vanderbilt.edu/images/staff/Bob-Wheaton.jpg"
let myFilePathString = "/Volumes/HD/Staff Pictures/Bob-VEHS.jpg"
let url = NSURL(string: myURLstring)
let imageDataFromURL = NSData(contentsOfURL: url)
let fileManager = NSFileManager.defaultManager()
fileManager.createFileAtPath(myFilePathString, contents: imageDataFromURL, attributes: nil)
If you're writing for OS X, you'll use NSImage instead of UIImage. You'll need import Cocoa for that - UIKit is for iOS, Cocoa is for the Mac.
NSData has an initializer that takes a NSURL, and another that takes a file path, so you can load the data either way.
if let url = NSURL(string: myURLstring) {
let imageDataFromURL = NSData(contentsOfURL: url)
}
let imageDataFromFile = NSData(contentsOfFile: myFilePathString)
With Swift 4, the code will be:
if let url = URL(string: myURLstring) {
let imageDataFromURL = try Data(contentsOf: url)
}

Resources