NSDataBase64DecodingOptions is returning nil value - json

I am trying to parse base64 type into imageData. But my NSDataBase64DecodingOptions returns nil. I printed decodedData and it is nil. My code is here
var base64String = arrayText["auto_type_android_img"] as String
println("basestring64 is \(base64String)")
let decodedData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))
println("base string is: \(decodedData)")
if let decodedImage = UIImage(data: decodedData!) {
imageTypeOfCar?.image = decodedImage
}

Your base64String is
data:image/png;base64,iVBORw0KGgoA......YII=
The initial "data:image/png;base64," is not part of the Base64
encoding and must be removed before the string can be decoded:
if let range = base64String.rangeOfString("data:image/png;base64,", options: .AnchoredSearch) {
base64String.removeRange(range)
}
Then
let decodedData = NSData(base64EncodedString: base64String, options: nil)
if let decodedImage = UIImage(data: decodedData!) {
imageTypeOfCar?.image = decodedImage
}
succeeds and displays

Related

swift how to add dictionary keys values in array

I am working on swift json Parsing where i am recieving json Data from Rest API for eg:
{"baseUrl":"http:\/\/localhost:9010\/",
"pluginOptions":{"values":[{"StartSyncTime":"2020-10-06 17:22:34","uuid":"977a5d03-2cdf-4008-87e6-01594e4369ef","LastSyncTime":"2020-10-06",
"MessageWrapper":{"Routing":"OriginSession","SourceSystem":"Mobile","MessageId":"51152ccd-32c6-475b-86a6-a2c883d551f5",
"UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"visurtest","Payload":"{}",
"DataType":"SQLLiteDDLAsync","MessageKind":"READ"}}],
"database":"structionDB","encrypted":false,"mode":"no-encryption"}}
I am getting as type [String:Any?] from rest api in below code
var pluginOptions : [String: Any]? = call.getObject("pluginOptions")
pluginOptions?[MessageWrapperKeys.DataType] = [DataTypes.SQLLiteDDLAsync]
pluginOptions?[MessageWrapperKeys.MessageKind] = [MessageKinds.READ]
pluginOptions?[MessageWrapperKeys.Payload] = ["{}"]
from above Json Response i need to extract MessageWrapper Dictionary like below
{"Routing":"OriginSession","SourceSystem":"VisurMobile","MessageId":"51152ccd-32c6-475b-86a6-a2c883d551f5",
"UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"visurtest","Payload":"{}",
"DataType":"SQLLiteDDLAsync","MessageKind":"READ"}
where above last 3 key vale i have added from code,Now i have to send Rest Api Call with above request but i did not able to figure it out how i will extraxt MessageWrapper Keys and append above 3 Key Values so that i get final jsonString Request like
{"Routing":"OriginSession","SourceSystem":"Mobile","MessageId":"05086b82-3623-492b-926a-d3bb8d01aa52","UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"test","Payload":"{}","DataType":"SQLLiteDDLAsync","MessageKind":"READ"}
below code i have triyed but not able to access
func readTableFromBackend(_ call: CAPPluginCall) -> Observable<String>{
var swrapper: [[String: Any]] = [[:]]
var pluginOptions : [String: Any]? = call.getObject("pluginOptions")
let json = JSON(pluginOptions)
var arrayNames = json["values"].arrayValue.map {$0["MessageWrapper"].string}
for arrayvalues in json["values"].arrayValue{
for arrayvalues in json["MessageWrapper"].arrayValue{
var string = arrayvalues["UserID"].string
}
var string = arrayvalues["MessageWrapper"].string
print(string)
}
pluginOptions?[MessageWrapperKeys.DataType] = [DataTypes.SQLLiteDDLAsync]
pluginOptions?[MessageWrapperKeys.MessageKind] = [MessageKinds.READ]
pluginOptions?[MessageWrapperKeys.Payload] = ["{}"]
var values = pluginOptions?["values"]
var modes = pluginOptions?["mode"]
for (key,value)in pluginOptions ?? ["":""]{
print("\(key) -> \(value)")
}
var finajsonstring: String = ""
var pluginOptions1: [String:Any] = [MessageWrapperKeys.DataType:DataTypes.SQLLiteDDLAsync, MessageWrapperKeys.MessageKind:MessageKinds.READ,MessageWrapperKeys.Payload: "{}"]
swrapper.append(pluginOptions ?? ["":""])
swrapper.append(pluginOptions1 )
let apidata = PullBackendData()
let plugindata = PluginCallParameterOptions()
var url: String? = call.getString("baseUrl")
// let payload = swrapper
let address = plugindata.getApiUrl(controllerName: Controllers.DataSync, baseUrl: url ?? "")
let jsonData = try? JSONSerialization.data(withJSONObject: pluginOptions)
guard let jsonString = String(data : jsonData!, encoding: .utf8
) else { return Observable.just("Error")}
let data = Data(jsonString.utf8)
do{
let newdata : NSDictionary = try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
}
if((newdata.value(forKey: "values")) != nil){
let info : NSArray = newdata.value(forKey: "values") as! NSArray
let info1 : NSArray = info.value(forKey: "MessageWrapper") as! NSArray
var wrapperarray: [[String:Any]] = [[String:Any]]()
wrapperarray = newdata.value(forKey: "values") as! [[String:Any]]
wrapperarray.append(pluginOptions1)
let jsonData: NSData = try JSONSerialization.data(withJSONObject: info1, options: []) as NSData
let jsonData2: NSData = try JSONSerialization.data(withJSONObject: wrapperarray, options: []) as NSData
do {
var jsonstring = try NSString(data: jsonData as Data, encoding: String.Encoding.utf8.rawValue)! as String
var jsonstring2 = NSString(data: jsonData2 as Data, encoding: String.Encoding.utf8.rawValue)! as String
//getting final string and sending to rest api
finajsonstring = jsonstring2 as String
}catch {
print("error")
}
}
} catch let error as NSError{
print(error)
}
let response = apidata.post(_for: address, bodyData: finajsonstring)
return Observable.from(optional: response)
}

How to store NSArray in Userdefaults?

Here is my code
var defaultValues = UserDefaults.standard
var json = NSArray()
self.defaultValues.set(json, forKey: "BedData")
I used this Code to store Strings and it works perfectly but when i tried to store NSArray it gives me this error "Attempt to insert non-property list object"
You have to encode and decode for adding and retrieving data to/from UserDefault.
func getUserDetail() -> UserDetail? {
if let decodedData = UserDefaults.standard.object(forKey: AppConstant.userDefaultKey.user_detail) as? Data {
return try! PropertyListDecoder().decode(UserDetail.self, from: decodedData)
}
return nil
}
func setUserDetail(user: UserDetail) {
UserDefaults.standard.set(try! PropertyListEncoder().encode(user), forKey: AppConstant.userDefaultKey.user_detail)
}
Thanks for the replies Guys But i have found the solution
Let json = NSArray()
To Store
let data = NSKeyedArchiver.archivedData(withRootObject: json)
self.defaultValues.set(data, forKey: "Offline-BedData")
And to Retrieve:
if let data = self.defaultValues.object(forKey: "Offline-BedData")! as? Data {
if let dict = NSKeyedUnarchiver.unarchiveObject(with: data) as? NSArray {
json = dict
print("json\(json)")
self.performSegue(withIdentifier: "BedShow", sender: Any?.self)
}
}

How to detect null JSON value in Swift 3?

I have a JSON object like this:
{
"access_token" = 593d6d5d5eca0;
"expires_in" = never;
user = {
fullname = name;
"profile_picture_url" = "<null>";
};
}
And here is my code to parse "profile_picture_url":
let profPicURL = URL(string: userData["profile_picture_url"] as! String)
let profPicData = NSData(contentsOf: profPicURL!)
let profilePicture = UIImage(data: profPicData as! Data)
But I got an error since the value of "profile_picture_url" was null.
How to parse "profile_picture_url" in safe way?
use if let
if let profileImageString = userData["profile_picture_url"] as? String {
let profPicURL = URL(string: "Hello moto")
let profPicData = try? Data(contentsOf: profPicURL!)
if let profPicData = profPicData {
let profilePicture = UIImage(data: profPicData)
}
} else {
// "profile_picture_url" was null
}

How can I decode JWT (JSON web token) token in Swift?

I have a JWT token like this
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
How can I decode this so that I can get the payload like this
{ "sub": "1234567890", "name": "John Doe", "admin": true }
If you are okay with using a library i would suggest this https://github.com/auth0/JWTDecode.swift
and then import the library import JWTDecode and execute.
let jwt = try decode(jwt: token)
Since you didn't want to include this library i brought out the needed parts to make it work.
func decode(jwtToken jwt: String) -> [String: Any] {
let segments = jwt.components(separatedBy: ".")
return decodeJWTPart(segments[1]) ?? [:]
}
func base64UrlDecode(_ value: String) -> Data? {
var base64 = value
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
let length = Double(base64.lengthOfBytes(using: String.Encoding.utf8))
let requiredLength = 4 * ceil(length / 4.0)
let paddingLength = requiredLength - length
if paddingLength > 0 {
let padding = "".padding(toLength: Int(paddingLength), withPad: "=", startingAt: 0)
base64 = base64 + padding
}
return Data(base64Encoded: base64, options: .ignoreUnknownCharacters)
}
func decodeJWTPart(_ value: String) -> [String: Any]? {
guard let bodyData = base64UrlDecode(value),
let json = try? JSONSerialization.jsonObject(with: bodyData, options: []), let payload = json as? [String: Any] else {
return nil
}
return payload
}
Call it like this:
decode(jwtToken: TOKEN)
Iterating on Viktor's code:
Use nested functions to keep more modular
Utilize exceptions if bad token passed or other errors.
Simpler calculation of padding and utilization of padding function.
Hope it is useful:
func decode(jwtToken jwt: String) throws -> [String: Any] {
enum DecodeErrors: Error {
case badToken
case other
}
func base64Decode(_ base64: String) throws -> Data {
let base64 = base64
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
let padded = base64.padding(toLength: ((base64.count + 3) / 4) * 4, withPad: "=", startingAt: 0)
guard let decoded = Data(base64Encoded: padded) else {
throw DecodeErrors.badToken
}
return decoded
}
func decodeJWTPart(_ value: String) throws -> [String: Any] {
let bodyData = try base64Decode(value)
let json = try JSONSerialization.jsonObject(with: bodyData, options: [])
guard let payload = json as? [String: Any] else {
throw DecodeErrors.other
}
return payload
}
let segments = jwt.components(separatedBy: ".")
return try decodeJWTPart(segments[1])
}
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
}
I have got the solution for this.
static func getJwtBodyString(tokenstr: String) -> NSString {
var segments = tokenstr.components(separatedBy: ".")
var base64String = segments[1]
print("\(base64String)")
let requiredLength = Int(4 * ceil(Float(base64String.characters.count) / 4.0))
let nbrPaddings = requiredLength - base64String.characters.count
if nbrPaddings > 0 {
let padding = String().padding(toLength: nbrPaddings, withPad: "=", startingAt: 0)
base64String = base64String.appending(padding)
}
base64String = base64String.replacingOccurrences(of: "-", with: "+")
base64String = base64String.replacingOccurrences(of: "_", with: "/")
let decodedData = Data(base64Encoded: base64String, options: Data.Base64DecodingOptions(rawValue: UInt(0)))
// var decodedString : String = String(decodedData : nsdata as Data, encoding: String.Encoding.utf8)
let base64Decoded: String = String(data: decodedData! as Data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
print("\(base64Decoded)")
return base64String as NSString
}
This works for me great. Thank you.
There's a swift implementation. Add this into your Podfile if you're using CocoaPods or clone the project and use it directly.
JSONWebToken
do {
// the token that will be decoded
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"
let payload = try JWT.decode(token, algorithm: .hs256("secret".data(using: .utf8)!))
print(payload)
} catch {
print("Failed to decode JWT: \(error)")
}
I you want to use a library for that I recommend using something popular from someone big. IBM is making Kitura – Swift backend framework, so the implementation of encoding and decoding JWT for it must be top notch:
Link:
https://github.com/IBM-Swift/Swift-JWT
Simple usage for token with expiry date
import SwiftJWT
struct Token: Decodable {
let jwtString: String
func abc() {
do {
let newJWT = try JWT<MyJWTClaims>(jwtString: jwtString)
print(newJWT.claims.exp)
} catch {
print("OH NOES")
}
}
}
struct MyJWTClaims: Claims {
let exp: Date
}
Objective-C version for oldies:
NSLog(#"credential is %#", credential.identityToken);
NSString * string = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding];
NSArray * segments = [string componentsSeparatedByString:#"."];
NSMutableDictionary * JSON = [NSMutableDictionary new];
for (int n = 0; n < segments.count; n++){
NSString * value = segments[n];
NSString * base64 = [value stringByReplacingOccurrencesOfString:#"-" withString:#"+"];
base64 = [base64 stringByReplacingOccurrencesOfString:#"_" withString:#"/"];
NSUInteger length = [base64 lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
int requiredLength = 4 * ceil((float)length/4.0f);
int paddingLength = requiredLength - (int)length;
for (int n = 0; n < paddingLength; n++){
base64 = [base64 stringByAppendingString:#"="];
}
NSData * data = [[NSData alloc] initWithBase64EncodedString:base64 options:0];
NSError * error;
NSDictionary * local = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&error];
[JSON addEntriesFromDictionary:local];
}
NSLog(#"JSON is %#", JSON);
I refactored #Viktor Gardart code
Use like this
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhY2NvdW56IiwianRpIjoiZTA0NGEyMTAtZjVmZi00Yjc2LWI2MzMtNTk0NjYzMWE0MjRjLWQxYTc3bXlpdGE0YnZnaG4yd2YiLCJleHAiOjE2NDk2NDI3MTF9.FO-AQhZ18qogsSbeTUY78EqhfL9xp9iUG3OlpOdxemE"
let jsonWebToken = JSONWebToken(jsonWebToken: token)
let expirationTime = jsonWebToken?.payload.expirationTime
JSONWebToken.swift
import Foundation
struct JSONWebToken {
let header: JSONWebTokenHeader
let payload: JSONWebTokenPayload
let signature: String
}
extension JSONWebToken {
init?(jsonWebToken: String) {
let encodedData = { (string: String) -> Data? in
var encodedString = string.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
switch (encodedString.utf16.count % 4) {
case 2: encodedString = "\(encodedString)=="
case 3: encodedString = "\(encodedString)="
default: break
}
return Data(base64Encoded: encodedString)
}
let components = jsonWebToken.components(separatedBy: ".")
guard components.count == 3,
let headerData = encodedData(components[0] as String),
let payloadData = encodedData(components[1] as String) else { return nil }
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
header = try decoder.decode(JSONWebTokenHeader.self, from: headerData)
payload = try decoder.decode(JSONWebTokenPayload.self, from: payloadData)
signature = components[2] as String
} catch {
print(error.localizedDescription)
return nil
}
}
}
JSONWebTokenHeader.swift
import Foundation
struct JSONWebTokenHeader {
let type: String
let algorithm: String
}
extension JSONWebTokenHeader: Codable {
private enum Key: String, CodingKey {
case type = "typ"
case algorithm = "alg"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: Key.self)
do { try container.encode(type, forKey: .type) } catch { throw error }
do { try container.encode(algorithm, forKey: .algorithm) } catch { throw error }
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
do { type = try container.decode(String.self, forKey: .type) } catch { throw error }
do { algorithm = try container.decode(String.self, forKey: .algorithm) } catch { throw error }
}
}
JSONWebTokenPayload.swift
import Foundation
struct JSONWebTokenPayload {
let issuer: String
let expirationTime: Double
let jsonWebTokenID: String
}
extension JSONWebTokenPayload: Codable {
private enum Key: String, CodingKey {
case issuer = "iss"
case expirationTime = "exp"
case jsonWebTokenID = "jti"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: Key.self)
do { try container.encode(issuer, forKey: .issuer) } catch { throw error }
do { try container.encode(expirationTime, forKey: .expirationTime) } catch { throw error }
do { try container.encode(jsonWebTokenID, forKey: .jsonWebTokenID) } catch { throw error }
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
do { issuer = try container.decode(String.self, forKey: .issuer) } catch { throw error }
do { expirationTime = try container.decode(Double.self, forKey: .expirationTime) } catch { throw error }
do { jsonWebTokenID = try container.decode(String.self, forKey: .jsonWebTokenID) } catch { throw error }
}
}

Swifty Json getting unknown but long way works fine?

I'm attempting to use SwiftyJson to pull some JSON data.
What's unusual is the "println(json)" says "unknowon" while if I pull the JSON data the regular way it works just fine -- the "println(pop)" says medium, as expected.
Below is the code I'm using. I started cutting out parts until I got to "println(json)" and then decided to try and handle it manually to see if it's SwiftyJson or me.
Any suggestions? I'm fairly new to iOS programming so I'm assuming I'm being silly in some form or another.
var ghostlandsJsonUrl: NSURL = NSURL(string: "http://us.battle.net/api/wow/realm/status?realm=Ghostlands")!
var jsonData: NSData!
var request: NSURLRequest = NSURLRequest(URL: ghostlandsJsonUrl)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
jsonData = data
if(jsonData != nil) {
let json = JSON(jsonData)
println(json)
} else {
println("jsonData: nil value... net down again?")
}
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let statuses = jsonObject as? NSDictionary{
if let realms = statuses["realms"] as? NSArray{
if let realm = realms[0] as? NSDictionary{
if let pop = realm["population"] as? NSString{
println(pop)
}
}
}
}
});
task.resume()
Looking at SwiftyJSON source code I can see that JSON is a simple struct. It implements the Printable protocol. Which give support to the print methods.
public var description: String {
if let string = self.rawString(options:.PrettyPrinted) {
return string
} else {
return "unknown"
}
}
Which means that for a reason or another the rawString method returns nil.
public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
switch self.type {
case .Array, .Dictionary:
if let data = self.rawData(options: opt) {
return NSString(data: data, encoding: encoding)
} else {
return nil
}
case .String:
return (self.object as String)
case .Number:
return (self.object as NSNumber).stringValue
case .Bool:
return (self.object as Bool).description
case .Null:
return "null"
default:
return nil
}
}
As you are fairly new to iOS development, I will tell you that the constructor doesn't expect a NSData object.
Here is the source:
public var object: AnyObject {
get {
return _object
}
set {
_object = newValue
switch newValue {
case let number as NSNumber:
if number.isBool {
_type = .Bool
} else {
_type = .Number
}
case let string as NSString:
_type = .String
case let null as NSNull:
_type = .Null
case let array as [AnyObject]:
_type = .Array
case let dictionary as [String : AnyObject]:
_type = .Dictionary
default:
_type = .Unknown
_object = NSNull()
_error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
}
}
}
So you should pass it the unserialized NSData as it:
if let jsonData = data {
//jsonData can't be nil with this kind of if
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
let json = JSON(jsonObject)
println(json)
//...
The constructor of JSON does the serialisation. Below is the constructor code from SwiftyJSON git repo where you can directly pass the NSData.
public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
do {
let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error.memory = aError
}
self.init(NSNull())
}
}
In simple, you can directly use the data returned in the completion handler of NSURLSession data task as below in your code.
let json = JSON(data: jsonData)