i have tried all solutions but still i none works for me. Here is my code (i use swift 4.2).
Error is : found nil while implicitly unwrapping an Optional value...
My data property is not empty.
var pdfic: WKWebView!
func pdfConv(id: String) -> WKWebView {
let data: Data = Data(base64Encoded: id, options: .ignoreUnknownCharacters)!
pdfic.load(data, mimeType: "application/pdf", characterEncodingName: "", baseURL:
URL(fileURLWithPath: ""))
return pdfic!
}
Can someone help me?
// Assuming id would be base64String
if let data = Data(base64Encoded: id, options: .ignoreUnknownCharacters) {
webView.load(data, mimeType: "application/pdf", characterEncodingName: "utf-8",
baseURL: URL(fileURLWithPath: ""))
}
Check if it works.
Related
It seems like "notes = JSON.parse(fs.readFileSync("notes-data.json"))" line of my code is not working as it should...
When I add new notes it should add on to the array in the .json file, but it just replaces the previous note.
let addNote = (title, body) => {
let notes = [];
let note = {
title,
body
};
notes.push(note);
fs.writeFileSync("notes-data.json", JSON.stringify(notes));
notes = JSON.parse(fs.readFileSync("notes-data.json"))
};
Code Screenshot:
Thank you in advance
If you want to add to the file contents, then you should really read the content before doing anything else:
let addNote = (title, body) => {
let notes;
try {
notes = JSON.parse(fs.readFileSync("notes-data.json")); // <---
} catch(e) {
notes = [];
}
let note = {
title,
body
};
notes.push(note);
fs.writeFileSync("notes-data.json", JSON.stringify(notes));
};
I'm trying to POST an array in Swift using Alamofire.
This is my Swift code:
var itemsToSend: [Dictionary<String, Any>] = []
for i in 0..<selectedSongs.count {
let app = ["Info" : selected[i]["Info"]!]
itemsToSend.append(app)
}
let toSend = try! JSONSerialization.data(withJSONObject: itemsToSend, options: [])
print(toSend) //142 bytes
let data: [String: Any] = [
"UID": FIRAuth.auth()?.currentUser?.uid as Any as! String,
"ID": "-",
"total" : selected.count,
"sendArray" : toSend
]
let URLString = "http://www.example.com/mult/"
Alamofire.request(URLString, method: .post, parameters: data, encoding: URLEncoding.default).responseString(completionHandler: { response in
print(response.result.value)
})
On my server, when I print sendArray I get: 142 bytes. How can I an array in Swift?
Don't convert it data simply set your array with your key sendArray.
let data: [String: Any] = [
"UID": FIRAuth.auth()?.currentUser?.uid!,
"ID": "-",
"total" : selected.count,
"sendArray" : itemsToSend
]
If you are using Alamofire, you don't need to use JSONSerialization, use JSONEncoding.default for encoding option when you are sending request
let data:[String: Any] = ["foo":"bar", "items":["this", "is", "an", "array"]]
// use JSONEncoding.default instead
Alamofire.request(URLString, method: .post, parameters: data, encoding: JSONEncoding.default).responseString(completionHandler: { response in
print(response.result.value)
})
on the server side, you will need to decode the post body using JSON decoder rather than URL decoder
My yeoman generator copies files from template to destination path:
this.fs.copyTpl(
this.templatePath(),
this.destinationPath(), {
appName: this.props.appName
});
During project generation, I need to assign value of this.props.appName to some of filenames.
Unfortunately I can't do this that way like I could do inside this files:
<%=appName%>-project.sln
All files that need to be renamed have appTemplate in their names, so what I need to do is simply replace appTemplate with value of this.props.appName.
Can I somehow configure copyTpl to rename some of files while copying them to another destination?
OK, I found a solution. According to yeoman docs:
Any generator author can register a transformStream to modify the file path and/or the content.
Using this method:
this.registerTransformStream();
What that means is I can pipe all generated files through some script:
var rename = require("gulp-rename");
//other dependecies...
module.exports = yeoman.Base.extend({
//some other things generator do...
writing: function() {
var THAT = this;
this.registerTransformStream(rename(function(path) {
path.basename = path.basename.replace(/(666replacethat666)/g, THAT.props.appName);
path.dirname = path.dirname.replace(/(666replacethat666)/g, THAT.props.appName);
}));
this.fs.copyTpl(
this.templatePath(),
this.destinationPath(), {
appName: this.props.appName
});
}
});
This script will pipe all files through gulp-rename, changing 666replacethat666 to something more intelligent.
If you cannot use registerTransformStream because you are using the composeWith() feature in Yeoman (which disconnects transform stream registrations), you can use the processDestinationPath, which works when you select multiple files (not when you specify a specific file in the first argument, for some reason).
this.fs.copyTpl(
this.templatePath("**/{.*,*}"),
this.destinationPath(),
{ /* usually your prompt answers are here */ },
{},
{
processDestinationPath: (filePath: string) =>
filePath.replace(/somedir\/a-file.js/g, 'newdir/better-filename.js'),
},
);
Source to documentation options: https://yeoman.github.io/generator/actions_fs.html#.copyTemplate
Which is based on https://github.com/SBoudrias/mem-fs-editor#copyfrom-to-options-context-templateoptions-
registerTransformStream with gulp-rename is still an issue. However, I get it working with glob.
const glob = require('glob');
writing() {
const files = glob.sync('**', { dot: true, nodir: true, cwd: this.templatePath() })
for (let i in files) {
this.fs.copyTpl(
this.templatePath(files[i]),
this.destinationPath( this.props.destinationFolderPath + '\\' + files[i].replace(/__fileName__/g,this.props.fileName)),
this.props
)
}
}
After copy, iterate over the paths of the output dir and regex replace all occurrences.
const getReplacement = (base, pathRel, match, replace) => {
let pathRelNew = pathRel.replace(match, replace);
let oldPathAbs = path.join(base, pathRel);
let newPathAbs = path.join(base, pathRelNew);
if (oldPathAbs != newPathAbs) {
return {
oldPath: oldPathAbs,
newPath: newPathAbs
}
}
}
const getReplacementsRecursive = (base, match, replace, replacements = []) => {
let pathsRel = fs.readdirSync(base);
pathsRel.forEach(pathRel => {
if (fs.statSync(path.join(base, pathRel)).isDirectory()) {
replacements = getReplacementsRecursive(path.join(base, pathRel), match, replace, replacements);
var replacement = getReplacement(base, pathRel, match, replace)
if (replacement) replacements.push(replacement);
} else {
var replacement = getReplacement(base, pathRel, match, replace)
if (replacement) replacements.push(replacement);
}
});
return replacements;
};
function replaceMatches(dir, match, replace) {
var replacements = getReplacementsRecursive(dir, match, replace);
replacements.forEach(function(replacement) {
fs.renameSync(replacement.oldPath, replacement.newPath);
});
}
module.exports = class extends Generator {
// ...
writing() {
// don't forget to set the output directory
let OUTPUT_DIR = "./out";
// this.fs.copyTpl(...);
// setTimeout is used to give some time for the copyTpl to finish
setTimeout(
() => {
var match = new RegExp( "666replacethat666", 'g' );
replaceMatches(OUTPUT_DIR, match, this.props.appName);
}, 1000);
}
}
Using Xcode 7 beta, Swift 2.0
I'm saving and loading credentials to keychain, somehow when loading I get "Optional(value)" back, it looks like this is really part of the string as it also displayed like so in a textbox or when sending to API
This is how I save and load credentials now, as you see I've done a lot of extra nil checking to make sure it is not nil or Optional, it is indeed a overuse of explanation marks...
func SaveCredentials(credentials : [String : String!]!) -> Bool
{
if(credentials.count == 2)
{
//only proceed when we have two keys: username and password
let username = credentials["username"]
let password = credentials["password"]
if let usernameStr = username
{//also tried username!=nil && password != nil
if let passwordStr = password
{ //usernameStr and passwordStr is of type String!
let NsDataUsername = usernameStr!.dataUsingEncoding(NSUTF8StringEncoding)
let NsDataPassword = passwordStr!.dataUsingEncoding(NSUTF8StringEncoding)
if(NsDataUsername != nil && NsDataPassword != nil)
{
LocalStorage.saveToKeyChain("username", data: NsDataUsername!)
LocalStorage.saveToKeyChain("password", data: NsDataPassword!)
return true
}
}
}
}
return false
}
func LoadCredentials() -> [String : String!]?
{
let NsDataUsername = LocalStorage.loadFromKeyChain("username")
let NsDataPassword = LocalStorage.loadFromKeyChain("password")
if(NsDataUsername != nil && NsDataPassword != nil)
{
let username : String! = String(NSString(data: NsDataUsername!, encoding: NSUTF8StringEncoding))
let password : String! = String(NSString(data: NsDataPassword!, encoding: NSUTF8StringEncoding))
if let usernameStr = username
{
if let passwordStr = password
{ // password is of type String!, passwordStr is of type String
var credentials : [String: String!] = [String : String]()
credentials["username"] = usernameStr
credentials["password"] = passwordStr
return credentials
}
}
}
return nil
}
And when I send to Api, this is my method that also requires a non-optional string. This method does work when logging in, getting strings from text fields, but does not filter out that Optional when coming from keychain.
func LoginUser(email : String!, password : String!)
{
print("LoginUser(email : \(email), password: \(password))")
var parameters = [String : AnyObject]()
parameters["UserName"] = email
parameters["Password"] = password
......
The strings that I send to the SaveCredentials method, are the same that the user logged in with:
func LoginLocalAccount(email : String!, password : String!)
{
databaseAPI.LoginUser(email!, password: password!) //login goes just fine
saveCredentials(email!, password: password!) //manages to get Optional in it..
}
I suspect it has something to do with saving and loading from keychain, for interests, this is what I use to save and load from keychain.
I want to get rid of them because when the app starts, it loads the credentials and tries to login at my API. Ofcourse I get an error back that the username is not a valid e-mail, because it is Optional(email#adress.com)
You're overusing !. You don't need them. Try to learn more about implicitly unwrapped optionals, optionals, ... Your code is a mess (no offense, everybody's learning).
Back to your optional problem, it's caused by this line:
let username : String! = String(NSString(data: NsDataUsername!, encoding: NSUTF8StringEncoding))
convenience init?(data: NSData, encoding: UInt) - inner part utilizes failable initializer, so, NSString? is the result. Then initialization of String with optional NSString? produces optional as well. But, it has no sense at all do it in this way.
First part - remove optional
Utilizing new guard:
guard let loadedPassword = NSString(data: passwordData, encoding: NSUTF8StringEncoding) else {
fatalError("Ooops")
}
loadedPassword contains NSString (not NSString?) now.
Second part - NSString -> String
You did probably read (if not, read) Strings and Characters about bridging, ... If you can freely exchange NSString with String, you can think that you're done:
var dict = [String:String]()
dict["password"] = loadedPassword
Nope. It produces following error:
NSString is not implicitly convertible to String; did you mean to
use 'as' to explicitly convert?
Slight change and now you're done:
var dict = [String:String]()
dict["password"] = loadedPassword as String
Complete example
let password = "Hallo"
guard let passwordData = password.dataUsingEncoding(NSUTF8StringEncoding) else {
fatalError("Ooops")
}
// save/load to/from keychain
guard let loadedPassword = NSString(data: passwordData, encoding: NSUTF8StringEncoding) else {
fatalError("Ooops")
}
var dict = [String:String]()
dict["password"] = loadedPassword as String
print(dict) // "[password: Hallo]\n"
I was wondering what the simplest and cleanest to read a text file into an array of strings is in swift.
Text file:
line 1
line 2
line 3
line 4
Into an array like this:
var array = ["line 1","line 2","line 3","line 4"]
I would also like to know how to do a similar thing into struct like this:
Struct struct{
var name: String!
var email: String!
}
so take a text file and put it into struct's in an array.
Thanks for the help!
First you must read the file:
let text = String(contentsOfFile: someFile, encoding: NSUTF8StringEncoding, error: nil)
Then you separate it by line using the componentsSeparatedByString method:
let lines : [String] = text.componentsSeparatedByString("\n")
Updated for Swift 3
var arrayOfStrings: [String]?
do {
// This solution assumes you've got the file in your bundle
if let path = Bundle.main.path(forResource: "YourTextFilename", ofType: "txt"){
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
arrayOfStrings = data.components(separatedBy: "\n")
print(arrayOfStrings)
}
} catch let err as NSError {
// do something with Error
print(err)
}
Updated for Swift 5:
The const path contains the file path.
do {
let path: String = "file.txt"
let file = try String(contentsOfFile: path)
let text: [String] = file.components(separatedBy: "\n")
} catch let error {
Swift.print("Fatal Error: \(error.localizedDescription)")
}
If you want to print what's inside of file.txt line by line:
for line in text {
Swift.print(line)
}
Here is a way to convert a string to an array(Once you read in the text):
var myString = "Here is my string"
var myArray : [String] = myString.componentsSeparatedByString(" ")
This returns a string array with the following values: ["Here", "is", "my", "string"]
Swift 4:
do {
let contents = try String(contentsOfFile: file, encoding: String.Encoding.utf8)
let lines : [String] = contents.components(separatedBy: "\n")
} catch let error as NSError {
print(error.localizedDescription)
}
In Swift 3 for me worked like below:
Import Foundation
let lines : [String] = contents.components(separatedBy: "\n")