Will be grateful for help
I get server response with strange dictionary format
Data: {
"featureHelpshift" = "true";
"featureAppleTVSynchronisation" = "false";
"featureDirectPlay" = "true";
"googleLoginSwitchOn" = "true";
"serverVersion" = "6.11.1";
"facebookLoginSwitchOn" = "true";
"allAvailableWorlds" = (
{
"name" = "\U0420\U043e\U0441\U0441\U0438\U044f 16 (\U043d\U043e\U0432\U044b\U0439)";
"mapURL" = "https://backend2.lordsandknights.com/maps/LKWorldServer-RU-16";
"worldStatus" = {
"id" = "3";
"description" = "online";
};
"country" = "RU";
"language" = "ru";
"id" = "190";
"url" = "https://backend2.lordsandknights.com/XYRALITY/WebObjects/LKWorldServer-RU-16.woa";
},...
first i try to serialize this response to JSON with swiftyJSON and json serializer
Than i get response as Data and parse it to String
func some () {
Alamofire.request(serverRequest, method: .post, parameters: parameters).responseData { response in
if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
//print("Data: \(utf8Text)") //- server response that shown above i print here
print("Change->")
let str = self.responseToJsonParsing(stringResponse: utf8Text)
print("Data: \(str)")
}
}
}
i try to lead my data string response to JSON string format, create function for parsing:
func responseToJsonParsing(stringResponse: String) -> String {
var parseResponse = stringResponse.replacingOccurrences(of: ";\n\t\t}", with: "\n\t\t}", options: .literal)
parseResponse = parseResponse.replacingOccurrences(of: ";\n\t\t\t}", with: "\n\t\t\t}", options: .literal)
parseResponse = parseResponse.replacingOccurrences(of: ";\n\t}", with: "\n\t}", options: .literal)
parseResponse = parseResponse.replacingOccurrences(of: ";\n}", with: "\n}", options: .literal)
parseResponse = parseResponse.replacingOccurrences(of: ";", with: ",")
parseResponse = parseResponse.replacingOccurrences(of: "=", with: ":")
parseResponse = parseResponse.replacingOccurrences(of: "(", with: "[")
parseResponse = parseResponse.replacingOccurrences(of: ")", with: "]")
return parseResponse
}
after parsing i still cant create JSON or Dictionary
Related
I am using the plugin to authenticate WordPress using api-rest : JWT Authentication for WP REST API
From the request to the server I get the following answer:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvbWlob3N0Lm9yZ1wvcHJ1ZWJhcyIsImlhdCI6MTU1MzcyNDM4MSwibmJmIjoxNTUzNzI0MzgxLCJleHAiOjE1NTQzMjkxODEsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.rgi5Q2c8RCoHRp-lJiJN8xQaOavn9T_q8cmf8v1-57o",
"user_email": "abc#test.com",
"user_nicename": "test",
"user_display_name": "Test"
}
So far everything works fine, but I need to know the user ID.
I have read that the token is coded in base64 and within this is the ID. Trying to decode, I see if the ID that I need is there.
In swift with this function I decode the token, but I can not get the dictionary ID.
func decode(_ token: String) -> [String: AnyObject]? {
let string = token.components(separatedBy: ".")
let toDecode = string[1] as String
var stringtoDecode: String = toDecode.replacingOccurrences(of: "-", with: "+") // 62nd char of encoding
stringtoDecode = stringtoDecode.replacingOccurrences(of: "_", with: "/") // 63rd char of encoding
switch (stringtoDecode.utf16.count % 4) {
case 2: stringtoDecode = "\(stringtoDecode)=="
case 3: stringtoDecode = "\(stringtoDecode)="
default: // nothing to do stringtoDecode can stay the same
print("")
}
let dataToDecode = Data(base64Encoded: stringtoDecode, options: [])
let base64DecodedString = NSString(data: dataToDecode!, encoding: String.Encoding.utf8.rawValue)
var values: [String: AnyObject]?
if let string = base64DecodedString {
if let data = string.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: true) {
values = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [String : AnyObject]
}
}
return values
}
The dictionary that returns this function is:
["iss": https://myhost.me/test, "exp": 1554235730, "nbf": 1553630930, "iat": 1553630930, "data": {
user = {
id = 2;
};
}]
How do I get the ID from this dictionary?
Your code is pretty unswifty.
Basically don't use NS... classes in Swift if there is a native equivalent and a JSON dictionary is always value type ([String:Any]).
I recommend to add an Error enum, make the function can throw, decode the serialized token with Decodable and return the Token instance on success
struct Token : Decodable {
let data : UserData
struct UserData : Decodable {
let user : User
struct User : Decodable {
let id : String
}
}
}
You are encouraged to keep the parameter label in the method declaration
enum TokenError : Error {
case invalidJWTFormat, invalidBase64EncodedData
}
func decode(token: String) throws -> Token {
let components = token.components(separatedBy: ".")
guard components.count == 3 else { throw TokenError.invalidJWTFormat }
var decodedString = components[1]
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
while decodedString.utf16.count % 4 != 0 {
decodedString += "="
}
guard let decodedData = Data(base64Encoded: decodedString) else { throw TokenError.invalidBase64EncodedData }
return try JSONDecoder().decode(Token.self, from: decodedData)
}
and call it
do {
let userID = try decode(token: "eyJ0eXAi.....").data.user.id
} catch { print(error) }
I have successfully parsed JSON for:
birthday = "04/10/1986";
id = 202038339983;
location = {
city = Jupiter;
country = "United States";
state = FL;
};
My question is when part of the JSON is:
submissions = {
data = (
{
"created_time" = "2018-02-16T05:11:56+0000";
id = "131448394823824_167398094382256";
viewer = "Any random string and/or emojis";
},
{
"created_time" = "2018-02-14T23:36:41+0000";
id = "809809871824_8908987486899";
message = "vday \Ud83d\Udda4\U2665\Ufe0f";
});}
How am I supposed to access created_time, id, viewer, and message?
I have been able to print the whole submissions JSON response to the console with this code :
guard let jsonD = responseFromServer as? [String : Any] else {return}
let subs1 = (jsonD["submissions"] as? [String : Any])
let accessSubs1 = theSubs1
guard let parsedPost = theSubs1 else {
return
}
My console will display:
["data": <__NSArrayI 0x6040001a86c0>(
{
"created_time" = "2018-02-16T05:11:56+0000";
id = "131448394823824_167398094382256";
viewer = "Any random string and/or emojis";
},
{
"created_time" = "2018-02-14T23:36:41+0000";
id = "809809871824_8908987486899";
message = "vday \Ud83d\Udda4\U2665\Ufe0f";
})]
My question is how should I parse the JSON so I can access the created_time inside submissions?
Here is the HTTP Request:
struct XClass: RequestProtocol {
var Path = "/User"
var parameters: [String : Any]? = ["stuff": "id, birthday, location, submissions"]
var aToken = aToken.current
var httpMethod: RequestHTTPMethod = .GET
var apiVersion: APIVersion = .defaultVersion
struct Response: ResponseProtocol {
var id = String()
var birthday = String()
var city = String()
var state = String()
var country = String()
var viewSubs = [String : Any]()
init(XResponse: Any?) {
guard let jsonD = XResponse as? [String : Any] else {return}
id = (jsonD["id"] as? String)!
birthday = (jsonD["birthday"] as? String)!
let XArr = (jsonD["location"] as? [String : String])
city = XArr!["city"]!
country = XArr!["country"]!
state = XArr!["state"]!
let subs1 = (jsonD["submissions"] as? [String : Any])
let accessSubs1 = theSubs1
guard let parsedPost = theSubs1 else {
return
}
viewSubs = theSubs1
}}}
func getXData(){
let connection = RequestConnection()
connection.add(XClass()) { response, result in
switch result {
case .success(let response):
print("Request Succeeded: \(response)\n\n\n")
case .failed(let error):
print("Request Failed: \(error)")
}}
connection.start()
}
Create a struct
struct Data: Decodable {
var created_time : String
var id : String
var viewer : String
}
call to the api url from URLSession
guard let url = URL(string: "your api url")
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error.localizedDescription)
} else {
guard let data = data else {return}
var data: [Data]() = JSONDecoder().decode(Data.self, data)
for dat in data{
print(dat.created_time)
print(dat.id)
print(dat.viewer)
}
}
If you are not using Decodable from Swift 4, or still in Swift 3,
then you can specify that the data in "submissions" is an array of dictionaries (double brackets) then you can iterate that.
Change
let subs1 = (jsonD["submissions"] as? [String : Any])
To
let subs1 = (jsonD["submissions"] as? [[String : Any]])
for sub in subs1 {
let time = sub["created_time "] as? [String : Any]
...
}
How could I use data in this kind of CSV file? Or how could I print for example row 2 value for "inside" column and assign it to a property / entity?
I have this kind of file I got from excel file converted to Numbers, I'd like to grab data for each column and use them.
The original CSV file opened in numbers:
The console output I got:
Using this methods:
func readDataFromCSV(fileName:String, fileType: String)-> String!{
guard let filepath = Bundle.main.path(forResource: fileName, ofType: fileType)
else {
return nil
}
do {
var contents = try String(contentsOfFile: filepath, encoding: .utf8)
contents = cleanRows(file: contents)
return contents
} catch {
print("File Read Error for file \(filepath)")
return nil
}
}
func cleanRows(file:String)->String{
var cleanFile = file
cleanFile = cleanFile.replacingOccurrences(of: "\r", with: "\n")
cleanFile = cleanFile.replacingOccurrences(of: "\n\n", with: "\n")
// cleanFile = cleanFile.replacingOccurrences(of: ";;", with: "")
// cleanFile = cleanFile.replacingOccurrences(of: ";\n", with: "")
return cleanFile
}
SOLUTION thanks to Jens Meder
using
func csv(data: String) -> [[String]] {
var result: [[String]] = []
let rows = data.components(separatedBy: "\n")
for row in rows {
let columns = row.components(separatedBy: ";")
result.append(columns)
}
return result
}
in viewDidLoad
var data = readDataFromCSV(fileName: kCSVFileName, fileType: kCSVFileExtension)
data = cleanRows(file: data!)
let csvRows = csv(data: data!)
print(csvRows[1][1]) // UXM n. 166/167
What you want to do is splitting up the string in rows and then into columns (basically a two dimensional array of Strings). Swift already provides the components method for that on String structs.
func csv(data: String) -> [[String]] {
var result: [[String]] = []
let rows = data.components(separatedBy: "\n")
for row in rows {
let columns = row.components(separatedBy: ";")
result.append(columns)
}
return result
}
Then you can access any value via:
var data = readDataFromCSV(fileName: kCSVFileName, fileType: kCSVFileExtension)
data = cleanRows(file: data)
let csvRows = csv(data: data)
print(csvRows[1][1]) //UXM n. 166/167.
Swift 4
Sometime CSV file is more complicated such as special characters (e.g. comma), the values are surrounded by double quotes as examples below:
Hello, "Complicated String, with a comma inside", 123
In this case, I use:
let dataString: String! = String.init(data: data!, encoding: .utf8)
var items: [(String, String, String)] = []
let lines: [String] = dataString.components(separatedBy: NSCharacterSet.newlines) as [String]
for line in lines {
var values: [String] = []
if line != "" {
if line.range(of: "\"") != nil {
var textToScan:String = line
var value:NSString?
var textScanner:Scanner = Scanner(string: textToScan)
while textScanner.string != "" {
if (textScanner.string as NSString).substring(to: 1) == "\"" {
textScanner.scanLocation += 1
textScanner.scanUpTo("\"", into: &value)
textScanner.scanLocation += 1
} else {
textScanner.scanUpTo(",", into: &value)
}
values.append(value! as String)
if textScanner.scanLocation < textScanner.string.count {
textToScan = (textScanner.string as NSString).substring(from: textScanner.scanLocation + 1)
} else {
textToScan = ""
}
textScanner = Scanner(string: textToScan)
}
// For a line without double quotes, we can simply separate the string
// by using the delimiter (e.g. comma)
} else {
values = line.components(separatedBy: ",")
}
// Put the values into the tuple and add it to the items array
let item = (values[0], values[1], values[2])
items.append(item)
print(item.1)
print(item.2)
print(item.3)
}
}
It is just written in Swift 4, the original is from https://www.appcoda.com/core-data-preload-sqlite-database/
Starting from iOS15 there is a new Official framework called TabularData, try to use it.
import TabularData
let url = Bundle.main.url(forResource: "csvFileName", withExtension: "csv")!
let result = try? DataFrame(contentsOfCSVFile: url)
print(result)
Then you can convert them into the data model you need
More Detail About TabularData(WWDC)
Swift 5.0
.scanLocaion and .scanUpTo() were deprecated in iOS13. Here's a working version of Chhaileng's answer.
func openCSV(fileName:String, fileType: String)-> String!{
guard let filepath = Bundle.main.path(forResource: fileName, ofType: fileType)
else {
return nil
}
do {
let contents = try String(contentsOfFile: filepath, encoding: .utf8)
return contents
} catch {
print("File Read Error for file \(filepath)")
return nil
}
}
func parseCSV(){
let dataString: String! = openCSV(fileName: "MeislinDemo", fileType: "csv")
var items: [(String, String, String)] = []
let lines: [String] = dataString.components(separatedBy: NSCharacterSet.newlines) as [String]
for line in lines {
var values: [String] = []
if line != "" {
if line.range(of: "\"") != nil {
var textToScan:String = line
var value:String?
var textScanner:Scanner = Scanner(string: textToScan)
while !textScanner.isAtEnd {
if (textScanner.string as NSString).substring(to: 1) == "\"" {
textScanner.currentIndex = textScanner.string.index(after: textScanner.currentIndex)
value = textScanner.scanUpToString("\"")
textScanner.currentIndex = textScanner.string.index(after: textScanner.currentIndex)
} else {
value = textScanner.scanUpToString(",")
}
values.append(value! as String)
if !textScanner.isAtEnd{
let indexPlusOne = textScanner.string.index(after: textScanner.currentIndex)
textToScan = String(textScanner.string[indexPlusOne...])
} else {
textToScan = ""
}
textScanner = Scanner(string: textToScan)
}
// For a line without double quotes, we can simply separate the string
// by using the delimiter (e.g. comma)
} else {
values = line.components(separatedBy: ",")
}
// Put the values into the tuple and add it to the items array
let item = (values[0], values[1], values[2])
items.append(item)
print(item.0)
print(item.1)
print(item.2)
}
}
}

This is for CSV file for swift 4.2
var dataArray = [[String]]()
if let path = Bundle.main.path(forResource: "file", ofType: "csv") {
dataArray = []
let url = URL(fileURLWithPath: path)
do {
let data = try Data(contentsOf: url)
let dataEncoded = String(data: data, encoding: .utf8)
if let dataArr = dataEncoded?.components(separatedBy: "\r\n").map({ $0.components(separatedBy: ";") }) {
for line in dataArr {
dataArray.append(line)
}
}
} catch let jsonErr {
print("\n Error reading CSV file: \n ", jsonErr)
}
}
Hey i am new to swift and I need to parse this JSON and get the value of "name" returned from a webservice:
{name = "Sameer Hussain";}
Here is my code so far:
var url: NSURL = NSURL(string: "http://xxxxxxxxx.com/xxxxx/xxxx.php")!
var request:NSMutableURLRequest = NSMutableURLRequest(URL:url)
var bodyData = "data=something"
request.HTTPMethod = "POST"
//request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue())
{
(response, data, error) in
// println(data)
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
//println(strData)
var err1: NSError?
var json2 = NSJSONSerialization.JSONObjectWithData(strData!.dataUsingEncoding(NSUTF8StringEncoding)!, options: .MutableLeaves, error:&err1 ) as! NSDictionary!
println("\(json2)")
}
From the code above it seems like your data is being saved within the json2 variable. To retrieve a value from that variable you can try something like this.
var userName: String?
var userAge: Int?
var userEmail: String?
if let parseJSON = json2
{
userName = parseJSON["name"] as? String
userAge = parseJSON["age"] as? Int
userEmail = parseJSON["email"] as? String
}
The above would work if your returned JSON looks something like this:
{
"name": "John"
"age": "21"
"email": "john#gmail.com"
}
what i've to do for getting, posting and checking data from a DB (MySQL) using swift?
Can I only create the php pages and contact them or there's a way to manage them? If yes, how?
(Sorry for my english)
Yes you need a php script
In your swift file:
var bodyData = "name=value" //To get them in php: $_POST['name']
let URL: NSURL = NSURL(string: "URL TO YOUR PHP FILE")
let request:NSMutableURLRequest = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue())
{
(response, data, error) in
var output = NSString(data: data, encoding: NSUTF8StringEncoding) // new output variable
var array = self.JSONParseArray(output)
}
in php:
function sendResponse($status = 200, $body = '', $content_type = 'text/html')
{
$status_header = 'HTTP/1.1 ' . $status;
header($status_header);
header('Content-type: ' . $content_type);
echo $body;
}
$name = $_POST['name']; // Like in the bodyData var
//Doing sql things
$result = array(
"result" => "VARIABLE TO SEND BACK"
);
sendResponse(200, json_encode($result));
And if you wan't to get the result in an array use this function:
func JSONParseArray(jsonString: String) -> Array<String> {
var e: NSError?
var data: NSData!=jsonString.dataUsingEncoding(NSUTF8StringEncoding)
var jsonObj = NSJSONSerialization.JSONObjectWithData(
data,
options: NSJSONReadingOptions(0),
error: &e) as Array<String>
if e == 0 {
return Array<String>()
} else {
return jsonObj
}
}