I am currently trying to write a script with Swift.
In the first run, the content was not written to the file.
But the second time it worked the same way.
Does anyone know how to solve it?
This is the code I wrote now.
func write_code_in_file(_ file_path: String,_ codes: String) {
let write_code = Process()
write_code.executableURL = URL(fileURLWithPath: "/usr/bin/env")
write_code.arguments = ["touch", current_path+file_path]
do {
try write_code.run()
} catch {
print("⚠️ Error - write code in file")
}
if let data: Data = codes.data(using: String.Encoding.utf8) { // String to Data
do {
try data.write(to: URL(fileURLWithPath: current_path + file_path))
} catch let e {
print("⚠️"+e.localizedDescription)
}
}
}
And the result value when you run it.
Related
Now I'm developing cloud functions.
Please teach me how to get data from call cloud functions using swift app.
I use TypeScript in cloud functions as backend service.
import * as functions from "firebase-functions"
import * as admin from "firebase-admin"
admin.initializeApp(functions.config().firebase)
export const helloWorld = functions
.https.onCall((data: any, context: any) => {
functions.logger.info("Hello logs!", { structuredData: true })
return { result: "Hello World" }
})
And in frontend I use swift.
func callCloudfunction(){
functions.httpsCallable("helloWorld").call(["name": "taro"]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
print(message)
}
}
if let data = (result?.data as? [String: Any]), let text = data["result"] as? String {
print("SUCCESS: \(text)")
}
}
}
In Swift I think functions.httpsCallable("helloWorld").call(["name": "taro"]) method is like http post request. So in TypeScript I can get the name's data using data argument.
But I don't know how to get result data from TypeScript. In TypeScript I created json { result: "Hello World" }.
How do I fix the process in swift? I think this code below is not good.
if let data = (result?.data as? [String: Any]), let text = data["result"] as? String {
print("SUCCESS: \(text)")
}
And please tell me how to handle error process.
Some class and property in error handling are already deprecated .FunctionsErrorDomain and FunctionsErrorDetailsKey.
Please teach me how to handle getting data and handle error process.
Thank you.
I am working on an app where I am trying to write data to a file. Basically the user can set the save directory and then I want to be able to check to see if the file exists. If it doesn't then create it and write the data. If it does exist I want to update/append a string to the end of the file. I have tried following many examples and guides online and it seems everyone is doing this differently. I apologize ahead of time if I am missing something super simple or if this has been asked a hundred times.
I have mostly been working off of this example with no success
Append text or data to text file in Swift
#IBAction func addVariance(_ sender: Any) {
let csvString = "08-06-2019,10:00 AM,10:23 AM,23,Offline,Test"
let directoryURL = URL(string: "/Users/username/Desktop/CSVtest")
let fileURL = directoryURL!.appendingPathComponent("/variances.csv")
let data = NSData(data: csvString.data(using: String.Encoding.utf8, allowLossyConversion: false)!)
if FileManager.default.fileExists(atPath: fileURL.path) {
var err:NSError?
if let fileHandle = try? FileHandle(forUpdating: fileURL) {
fileHandle.seekToEndOfFile()
fileHandle.write(data as Data)
fileHandle.closeFile()
}
else {
print("Can't open fileHandle \(String(describing: err))")
}
}
else {
var err:NSError?
do {
try data.write(to: URL(fileURLWithPath: fileURL.path), options: .atomic)
} catch {
print(error)
}
}
}
When trying to run this function when there is a file in the folder named "variances.csv" I get "Can't open fileHandle nil".
I have tried break points and print() lines. It doesn't seem to be getting past "if let fileHandle = try? FileHandle(forUpdating: fileURL)" and I can't figure out why. fileURL is not nil.
When I try running this function outputting to an empty directory I get.
"Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “variances.csv” in the folder “CSVtest”." UserInfo={NSFilePath=/Users/username/Desktop/CSVtest/variances.csv, NSUnderlyingError=0x600000c9eaf0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}"
I am trying to create JSON Web Token using JSONSerialization class, Swift 3 and Xcode 8.1, but my project fails to build with error:
Command failed due to signal: Segmentation fault 11.
Anyone knows why my code is not correct?
If I comment out this code from the project, the project builds.
let customerError = "Custom Error"
enum headerError: Error {
case customerError
}
let headerJWT: [Dictionary] = ["alg":"RS256","typ":"JWT"]
//Convert headerJWT to Data
do {
let headerJWTData: Data = try? JSONSerialization.data(withJSONObject:headerJWT,options: JSONSerialization.WritingOptions.prettyPrinted)
} catch headerError.customerError {
print("could not make data")
}
//Convert headerData to string utf8
do {
let headerJWTString = try String(data: headerJWTData,encoding:String.Encoding.utf8) as! String
} catch {
print("string could not be created")
}
//Convert headerJWTString to base64EncodedString
do {
let headerJWTBase64 = try Data(headerJWTString.utf8).base64EncodedString()
} catch {
"base64 could not be created"
}
Once you create the Data from using JSONSerialization, you simply use the method from Data to get a base64 encoded string.
let headerJWT: [Dictionary] = ["alg":"RS256","typ":"JWT"]
do {
let headerJWTData: Data = try? JSONSerialization.data(withJSONObject:headerJWT,options: JSONSerialization.WritingOptions.prettyPrinted)
let headerJWTBase64 = headerJWTData.base64EncodedString()
} catch headerError.customerError {
print("could not make data")
}
You can pass different options to base64EncodedString() depending on what format you need the base64 string to be in.
I have Alamofire added through cocoapods and I have a method going to download a zip file (approx 50Mb).
While downloading everything looks perfect. I can see in Activity Monitor that 50Mb is downloaded for my app, I can see the progressbar zinging across. But I can never find the file.
Right now I have it set to use the current directory, but have tried others just in case. I have even searched the entire drive by data modified and never find anything.
Here is my code.
func downloadAndInstall(){
log.info("Downloading and Installing.....")
displayToUser(content: "Downloading and Installing.....")
let urlString = updatePackageURL //(This is http://xxxx.com/xxxxpackage.zip)
let fileManager = FileManager.default
currentDir = fileManager.currentDirectoryPath
let fileURL: URL = URL(string: currentDir + "/package.zip")!
let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
log.info("FILEURL: \(fileURL)")
var progressValues: [Double] = []
var response: DefaultDownloadResponse?
Alamofire.download(urlString, to: destination)
.downloadProgress { progress in
progressValues.append(progress.fractionCompleted)
log.info("Latest Progress Value: \(progress.fractionCompleted)")
self.progBar.doubleValue = progress.fractionCompleted
}
.response { resp in
response = resp
if progressValues.last != 1.0 {
//backout of the process, something went wrong
log.debug("Something went wrong downloading the file. Close and try again.")
self.displayToUser(content: "Something went wrong downloading the file. Close and try again.")
self.exitpoorly()
}
else{
log.info("Download Finished")
self.displayToUser(content: "Download Finished")
self.extractpackage()
}
}
var previousProgress: Double = progressValues.first ?? 0.0
for progress in progressValues {
previousProgress = progress
}
if let lastProgressValue = progressValues.last {
log.info("Current Download Value: \(lastProgressValue, 1.0)")
} else {
//Fail
}
}
I'd suggest checking for any errors, e.g.:
Alamofire.download(urlString, to: destination)
.downloadProgress { progress in
...
}
.response { response in
guard response.error == nil else {
//backout of the process, something went wrong
log.debug("Something went wrong downloading the file. Close and try again.")
log.debug(response.error!.localizedDescription)
...
self.exitpoorly()
return
}
log.info("Download Finished")
...
}
Maybe the app is sandboxed, or perhaps you don't have permissions for that folder. It's hard to say without seeing the error.
Try to read some information from system profiler. For this purpose i m running some terminal line commands with NSTask. If i run some command which output not too big there is no problem.(For example : SPInstallHistoryDataType) But if i run "SPApplicationsDataType" command to collect installed application list, NSTask waits too much without any result and any error.
So i started to thing there should be a buffer size or something like that and i could not find anything about that. I don't know maybe i m on wrong way.
func readData (dataType: String) -> NSArray? {
let out = NSPipe()
let task = NSTask()
task.launchPath = "/usr/sbin/system_profiler"
task.arguments = ["-xml",dataType]
task.standardOutput = out
task.launch()
task.waitUntilExit()
if task.terminationStatus != 0 {
NSLog("system_profiler returned error status")
return nil
}
let data = out.fileHandleForReading.readDataToEndOfFile()
let plist : AnyObject?
do {
plist = try NSPropertyListSerialization.propertyListWithData(data,
options: [.Immutable],
format: nil)
} catch let error as NSError {
NSLog("%#", "Failed to parse system_profiler results. \(error.localizedDescription)")
return nil
}
return plist as? NSArray
}
let r = readData("SPInstallHistoryDataType")// There is no problem
let r2 = readData("SPApplicationsDataType") // Crash
Note : Yes i could write this data to file and read from that file. But i try to understand what is the problem.
It's definitely a buffer issue. When you read a chunk at a time, it works.
func getApplications() -> String?
{
var retval=""
let theTask = NSTask()
let taskOutput = NSPipe()
theTask.launchPath = "/usr/sbin/system_profiler"
theTask.standardOutput = taskOutput
theTask.standardError = taskOutput
theTask.arguments = ["-xml", "SPApplicationsDataType"]
theTask.launch()
while (true) {
let data = taskOutput.fileHandleForReading.readDataOfLength(1024)
if (data.length <= 0) { break }
let str = String(data: data, encoding: NSUTF8StringEncoding)!
retval += str
//print (str)
}
theTask.waitUntilExit()
return retval
}
I have a similar problem, on a new Mac Pro, but even worse. With macOS 10.15.3 Catalina I am not able to get system_profiler data for "SPAudioDataType". Other processes like curl etc. can be called but system_profiler is a problem.
The very funny thing with my problem was, that is only occurred about 10 minutes after making a fresh restart. In the first 10 minutes everything worked, with or without using handlers and even with the code "getApplications" from the answer above.
And yes, of course I run it in the main thread, but it makes no difference running in main thread or not.
I experimented lot to look, what is the source for this behavior. I found out, that my programs hangs while reading data with the command
let data = taskOutput.fileHandleForReading.readDataOfLength(1024)
in the case that there is error data available and vice versa the program hangs while reading error messages with the command
let data = taskError.fileHandleForReading.readDataOfLength(1024)
in the case that there is normal data available (but no error data).
The Program even hangs if I tried to get the amount of data, which is currently available:
let c = taskError.fileHandleForReading.availableData.count
Regardless what I test first, the program hangs if there is no data available.
So I completely rewrote my function to using async handlers:
#discardableResult func launchprogram (_ launchpath: String, _ arguments: [String]) -> (result: String, error: Int)
{
var out: String = "" // Output
var err: String = "" // Error Messages
var fin: Bool = false // If the process exits normally
let pro: Process = Process()
pro.arguments = arguments
pro.launchPath = launchpath
pro.standardOutput = Pipe()
pro.standardError = Pipe()
let proOut: Pipe = pro.standardOutput as! Pipe
let proIn: Pipe = pro.standardError as! Pipe
proOut.fileHandleForReading.readabilityHandler =
{
pipe in
if let line = String(data: pipe.availableData, encoding: String.Encoding.utf8)
{
if line.count > 0 // Neuen Ausgabe-Text hinzufügen
{
out += line
}
}
}
proIn.fileHandleForReading.readabilityHandler =
{
pipe in
if let line = String(data: pipe.availableData, encoding: String.Encoding.utf8)
{
if line.count > 0 // Neuen Fehler-Text hinzufügen
{
err += line
}
}
}
pro.terminationHandler =
{
(process) in
fin = not(process.isRunning)
}
pro.launch()
pro.waitUntilExit()
if err == ""
{
if fin
{
return (out, 0)
}
else
{
return (out, -1)
}
}
else if out == ""
{
let message: String = "Error while executing:" + char(13) + char(13)
return (message + err, -2)
}
else
{
let message: String = char(13) + char(13) + "Error while executing:" + char(13) + char(13)
return (out + message + err, -3)
}
}
The fundamental difference between this function and the function "getApplications" from the last post is, that I use "handler" to manage the output und error message streams. This always works. Deployment Target can bei 10.9 or above. I did not test it with 10.8 and earlier. So my problem was, that in Catalina under some circumstances it is not longer possible to get the information in "normal" synchronous order but only async with using handlers. If I break the execution, I always be in something like "libsystem_kernel.dylibread" withe the calling function "Foundation_NSReadFromFileDescriptorWithProgress". I would be glad to know, if this is a Catalina issue (with a new Mac Pro) or a fundamental change in what Apple wants us to use.