Swift Filemanager fails to create temporary directory - swift

This Code:
let csvString = self.generateCSV()
let tmpURL = try FileManager.default.url(for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
let tempFileUrl = tmpURL.appendingPathComponent("App-DigiAufklaerung-\(self.formatDateToPrecision(Date())).csv")
let data = csvString.data(using: .utf8)
try data?.write(to: tempFileUrl,
options: .atomic)
self.csvFile = tempFileUrl
(I thought) should create a tmp file, from which i can then share the cdv through AirDrop, but the creation of the tmpDir fails, what am i doing wrong here?
This error message was printed several times:
CFURLSetTemporaryResourcePropertyForKey failed because it was passed an URL which has no scheme

Related

Running A Shell Script With Swift in Cocoa

I'm working on a Mac desktop app and trying to run a shell script. I'm getting hung up on setting a launch path for the task. Here's the code:
let path = fileURL.deletingLastPathComponent().relativePath
//set new filename
let strNewFileName = fileURL.deletingPathExtension().lastPathComponent.appending(".html")
let newPath = path + "/" + strNewFileName
//create script
var strScript = "pandoc -s -o "
strScript.append(newPath)
strScript.append(" ")
strScript.append(fileURL.absoluteString)
//set storage path
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
var documentPath:URL = URL(string: documentsPath)!
documentPath.appendPathComponent("pandoc.sh")
var myURLComponents = URLComponents()
myURLComponents.scheme = "file"
myURLComponents.path = documentPath.absoluteString
do {
//write file
try strScript.write(to: myURLComponents.url!, atomically: true, encoding: String.Encoding.utf8)
//run script
let myTask = Process()
myTask.launchPath = "/usr/bin/env"
myTask.arguments = [strScript]
let myPipe = Pipe()
myTask.standardOutput = myPipe
myTask.launch()
let data = myPipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
print(output!)
} catch {
print(error.localizedDescription)
}
This throws a no such file error:
env: pandoc -s -o /Users/stevensuranie/Desktop/MarkdownFiles/targeting-params-ios.html file:///Users/stevensuranie/Desktop/MarkdownFiles/targeting-params-ios.md: No such file or directory
Any help would be appreciated.
This line cannot work
var documentPath:URL = URL(string: documentsPath)!
URL(string is for URL strings including the scheme (file:// or https://), for file system paths you must use URL(fileURLWithPath.
However if you use the URL related API of FileManager you can avoid the init method at all.
A similar issue is absoluteString, never call it on a file system URL, use always path.
A second fatal issue is that each shell argument must be an item in the arguments array and the executable must be specified with the full path
//create script
let scriptArguments = ["/path/to/pandoc", "-s", "-o", newPath, fileURL.path]
//set storage path
let documentsURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let scriptURL = documentsURL.appendingPathComponent("pandoc.sh")
The following lines are redundant
var myURLComponents = URLComponents()
myURLComponents.scheme = "file"
myURLComponents.path = documentPath.absoluteString
The write the string to scriptURL
do {
//write file
try strScript.write(to: scriptURL, atomically: true, encoding: .utf8)
...
myTask.arguments = scriptArguments
And finally don't use NS... classes in Swift
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
Use the native equivalent
let output = String(data: data, encoding: .utf8)

create plist and copy it to folder MacOS Swift

I have been racking my brain on how to create and write a plist to a certain Folder Directory in MacOS. In my case to the LaunchDaemons folder in /Library. I know how to create the plist but its the writing to the LaunchDaemons folder that I am having issues with. This code below from my understanding is for the sandbox but how do I do it outside of the sandbox? Cheers
let fileManager = FileManager.default
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let path = documentDirectory.appending("test.plist")
I have added the code with the help I have received and have no errors but it is not writing anything to the folder. Here is the code:
let libraryDirectory = try! FileManager.default.url(for: .libraryDirectory, in: .localDomainMask, appropriateFor: nil, create: false)
let launchDaemonsFolder = libraryDirectory.appendingPathComponent("LaunchDaemons/test.plist")
if FileManager.default.fileExists(atPath: launchDaemonsFolder.path) {
print(launchDaemonsFolder)
let plistDictionary : [String: Any] = [
"ExitTimeOut": 600,
"Label": "BOOT.SHUTDOWN.SERVICE",
"ProgramArguments": ["/test.sh"] as Array,
"RunAtLoad": false,
"WorkingDirectory": "/"
]
let dictionaryResult = NSDictionary(dictionary: plistDictionary)
let fileWritten = dictionaryResult.write(to: launchDaemonsFolder, atomically: true)
print("is the file created: \(fileWritten)")
} else {
print("File Exists")
}
First of all NSSearchPathForDirectoriesInDomains is outdated, it's highly recommended to use the URL related API anyway.
This code creates an URL pointing to /Library/LaunchDaemons
let libraryDirectory = try! FileManager.default.url(for: .libraryDirectory, in: .localDomainMask, appropriateFor: nil, create: false)
let launchDaemonsFolder = libraryDirectory.appendingPathComponent("LaunchDaemons")

Swift 4 alternative if let

I have this code, it checks if a file exists in the document directory, if it does it used this to set up the data for the controller, if it doesn't it uses a file supplier in the bundle, and if also that fails it set up an empty view controller.
Is there a way to conditionally set the url variable so that I can write the parse(fromFile:) method once instead of in an if else? The most intuitive way would appear to be if let url = something || let url = somethingElse then perform in the parse(fromFile: url) in the brackets, but it appears that it's not possible with swift.
if let url = try? FileManager().url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true).appendingPathComponent("database.json") {
parse(fromFile: url)
} else if let url = Bundle.main.url(forResource: "database", withExtension: "json") {
parse(fromFile: url)
} else {
setUpWithNothing()
}
I would recommend to split the code into several steps:
let documentsUrl = try! FileManager.default.url(
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true
)
The documents directory should always exists therefore I am not too worried about using try!. However, if you worry, you should solve that special case separately, e.g. using:
guard let documentUrl = try? ... else {
setUpWithNothing()
return
}
Then:
let fileUrl = documentUrl.appendingPathComponent("database.json")
This call never fails, it doesn't check the existence of the file. You need to check existence explicitly:
let fileExists = FileManager.default.fileExists(atPath: fileUrl.path)
let defaultUrl = Bundle.main.url(forResource: "database", withExtension: "json")
let databaseUrl = fileExists ? fileUrl : defaultUrl!
Again, you shouldn't worry about the existence of the file in your bundle, if you know it's there and simply call:
parse(fromFile: databaseUrl)
However, if you want to be extra careful, just remove the ! and use:
if let databaseUrl = fileExists ? fileUrl : defaultUrl {
parse(fromFile: databaseUrl)
} else {
setUpWithNothing()
}
You can use the nil-coalescing operator (??):
If the expression with FileManager returns nil (by throwing, thanks to the try?), then Bundle.main.url(...) will be used instead.
If that is also nil, then the conditional binding will fail entirely, and the else block will be run setUpWithNothing().
if let url = (try? FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true
).appendingPathComponent("database.json"))
?? Bundle.main.url(forResource: "database", withExtension: "json") {
parse(fromFile: url)
} else {
setUpWithNothing()
}
Since you're doing the same thing in the first two cases and something different in the second, this is a good candidate for it's own function:
func databaseFileURL() -> URL? {
if let url = try? FileManager().url(for: .documentDirectory, in: .userDomainMask,
appropriateFor: nil, create: true) {
return url.appendingPathComponent("database.json")
}
else {
return Bundle.main.url(forResource: "database", withExtension: "json")
}
}
and then you can just do
if let url = databaseFileURL() {
parse(fromFile: url)
} else {
setUpWithNothing()
}
It nicely separates concerns and makes it cleaner and clearer at the point of use. And if you need to do anything else with the file you can just call the function rather than copy-pasting the logic.

File cannot be opened - however it does exist - swift 3

I am recording video to a file with this code:
print(documentsPath)
//var/mobile/Containers/Data/Application/FFB207E7-36CC-4C53-A2E2-5FADC7C23A18/Documents/gymnastVideos/test.mp4
let filePath = NSURL(fileURLWithPath: documentsPath)
videoFileOutput.startRecording(toOutputFileURL: filePath as URL!, recordingDelegate: recordingDelegate)
and have verified that the file exists, however, when I try to open the file to check if anything is being saved there, I return an error. The code:
var documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
documentsPath.append("/gymnastVideos")
let filePath = URL(fileURLWithPath: documentsPath)
do {
let directoryContents = try FileManager.default.contentsOfDirectory(at: filePath, includingPropertiesForKeys: nil, options: [])
print(directoryContents)
print("!")
} catch let error as NSError {
print(error.localizedDescription)
//The file “gymnastVideos” couldn’t be opened.
print("!!")
}
Why can't I open the file, and what do I need to change in my code to be able to open the file?

Sqlite error in while appending file

I am ne to iOS developer i want to one thing that when i connect Sqlite with Xcode then after appending the code in nsobject class the error comes second line that instance member documents cannot be used type of class name
Here is code-
let documents = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let fileURL = documents.URLByAppendingPathComponent("test.sqlite")
var db: COpaquePointer = nil
if sqlite3_open(fileURL, &db) == SQLITE_OK {
print("Successfully opened connection to database at \(fileURL)")
return db
} else {
print("Unable to open database. Verify that you created the directory described " +
"in the Getting Started section.")
}
Please resolve my problem
It would appear that you're trying to declare fileURL outside of a method. If this is a property, you can't reference documents like that. So, either make this a local variable of your method, or collapse these two declarations into a single statement:
In Swift 3:
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("test.sqlite")!
In Swift 2:
let fileURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
.URLByAppendingPathComponent("test.sqlite")!
That avoids referencing documents at all.
As an aside, you can't pass fileURL to the sqlite3_open function. You should use fileURL.path (or, in Swift 2, fileURL.path!).