I have an api that creates a JWT for a logged in user and when I look at the decoded version of the token on jwt.io I get what I expect.
It shows that the data property is [] and it holds the users data when a user is logged in.
Now I am trying to decode this into swift for my iOS app, but the data in the data property comes back as:
(
)
and the type for this is __NSArray0
I can't loop through it or anything - what is a __NSArray0 and how would decode the token properly?
__NSArray0:
__NSArray means it's an NSArray object. It's the "old Objective-C immutable Array type". That's what gives you after decoding an JSON Array with (NS)JSONSerialization if you don't cast it into a Swift Array.
The 0 at the end is to say it's a specific NSArray, it's an NSArray empty, with no object. Why using that? Because in reality, it's a internal version of NSArray that is optimized for zero elements. So don't mind about it.
Since you have a NSArray, typical print of it, is:
(
)
So just cast it as an Array how its supposed type when non-empty to iterate. If you know it's an array of String, cast is as [String] and iterate over it.
It's the OpenStep format. Did you ever tried to read a PBXCodeProj?
Like more yourApp.xcodeproj/project.pbxproj It's there, you see how are printed NSDictionary, NSArray etc in that Format + comments.
In JSON, it's [] to show it's an Array, but in Objective-C the print is different.
Want to reproduce it?
let emptyNSArray = NSArray()
print("emptyNSArray:\n\(emptyNSArray)")
let castedEmptyAsArray = emptyNSArray as [AnyObject]
print("castedEmptyAsArray:\n\(castedEmptyAsArray)")
let nsArray = NSArray(array: ["Hello", "World", "!"])
print("nsArray:\n\(nsArray)")
let castedAsArray = nsArray as [AnyObject]
print("castedAsArray:\n\(castedAsArray)")
let emptyArrayJSON = Data("[]".utf8)
let decodedEmptyArrayDefault = try! JSONSerialization.jsonObject(with: emptyArrayJSON)
print("decodedEmptyArrayDefault:\n\(decodedEmptyArrayDefault)") //If you don't cast, it's by default a NSArray
let decodedEmptyArrayCasted = try! JSONSerialization.jsonObject(with: emptyArrayJSON) as! [AnyObject]
print("decodedEmptyArrayCasted:\n\(decodedEmptyArrayCasted)")
Output:
$>emptyNSArray:
(
)
$>castedEmptyAsArray:
[]
$>nsArray:
(
Hello,
World,
"!"
)
$>castedAsArray:
[Hello, World, !]
$>decodedEmptyArrayDefault:
(
)
$>decodedEmptyArrayCasted:
[]
Related
I have problems to cast my array of type 'result' to an array of string. This is what I already tried:
EDIT:
I need the information as String type since I want to use the URL as image source.
swift4
let message = try? JSONDecoder().decode(Welcome.self, from: data)
let imageURLs = message?.children.attachment.results.filter({ $0.metadata.mediaType == "image/png" })
let latestImageURls = imageURLs?.prefix(2)
let latestImageURlsArray = Array(latestImageURls ?? [])
let image1 = self.view.viewWithTag(63) as! UIImageView
let image2 = self.view.viewWithTag(64) as! UIImageView
let image3 = self.view.viewWithTag(65) as! UIImageView
let url1 = URL(string: latestImageURlsArray[0]) // error:Cannot convert value of type 'Result' to expected argument type 'String
let url2 = URL(string: latestImageURlsArray[1]) // error:Cannot convert value of type 'Result' to expected argument type 'String
let url3 = URL(string: latestImageURlsArray[2]) // error:Cannot convert value of type 'Result' to expected argument type 'String
image1.kf.setImage(with: url1)
image2.kf.setImage(with: url2)
image3.kf.setImage(with: url3)
I think there is no such thing as [Array], I guess you're talking about Array<Result>. An array of Result object. What is the same as [Result].
If for some reason you want to create a new Array object from you ArraySlice, just call an initializer.
let resultsArray = Array(latestImageURls ?? [])
UPDATE
You're saying that you also need to convert your Result objects into String, but you disn't explain what is the Result object and how does it how is it related to the String. Does it contain it or it is a String? So I'll try to assume.
If you want to cast you objects into String, you can do it like that
let latestImageURlsArray = resultsArray.compactMap { $0 as? String }
If you want to extract your strings from results if they have it, (let's say that it's stored at imageURL parameter) you can do it like that
let latestImageURlsArray = resultsArray.compactMap { $0.imageURL }
After that, latestImageURlsArray will be an [String].
If the relation is completely different and more complicated, please add more details about the Result class, so I could make my answer more specific.
You're not doing any "casting", you're just saying "I expected a [Array]". You're not doing anything to make that be the case. In any case, that's not even valid, because Array isn't a valid type.
As you see, prefix returns an ArraySlice<T>, which provides a lightweight view into the memory of Array<T>, without copying any elements.
In general, the way you convert an ArraySlice of a given type to an Array of that type is to use the Array initializer:
struct Thing {
}
let things = [Thing]()
let sliceOfArrayOfThings = things.prefix(2)
let arrayOfThings = Array(sliceOfArrayOfThings)
In your case your Array is actually an Optional array, so you have to take some extra steps to deal with the optionality, as described by Yury in his answer:
let things: [Thing]? = []
let sliceOfArrayOfThings = things?.prefix(2)
let arrayOfThings = Array(sliceOfArrayOfThings ?? [])
I've got a server response returning
(
{
agreementId = "token.virtual.4321";
city = AMSTERDAM;
displayCommonName = "bunch-of-alphanumeric";
displaySoftwareVersion = "qb2/ene/2.7.14";
houseNumber = 22;
postalCode = zip;
street = "";
}
)
how do I get the value of agreementId? response['agreementId'] is not working. i've tried some example code with .first but I cannot get it working.
Some extra information, I do a http call to a server with alamofire. I try to parse the json to a constant response:
let response = JSON as! NSDictionary
However that returns a error message
Could not cast value of type '__NSSingleObjectArrayI' (0x1083600) to 'NSDictionary' (0x108386c).
So now parse the json to an array, which seems to be working. The code above is what
let response = JSON as! NSArry
print(response)
spits out.
Now I only need to retrieve the value from the key "agreementId" and I have no clue how to do that.
In swift you need to use Swift's native type Array/[] and Dictionary/[:] instead of NSArray and NSDictionary, if you specify the type like above means more specific then the compiler won't complain. Also use optional wrapping with if let or guard let to prevent crash.
if let array = JSON as? [[String:Any]] {//Swift type array of dictionary
if let dic = array.first {
let agreementId = dic["agreementId"] as? String ?? "N/A"//Set default value instead N/A
print(agreementId)
//access the other key-value same way
}
}
Note: If you having more than one object in your array then you need to simply loop through the array to access each dictionary of array.
if let array = JSON as? [[String:Any]] {//Swift type array of dictionary
for dic in array {
let agreementId = dic["agreementId"] as? String ?? "N/A"//Set default value instead N/A
print(agreementId)
//access the other key-value same way
}
}
I'm trying to create a Base64-String in Swift. I have an example of a Base64-encoded string and its array-counterpart. My problem now is, that I don't know how I get an equivalent array to the one which is given in the example.
Because I didn't want to mess around in my XCode-project I did the following in a playground.
given array:
{"WHERE":{"Class":"%3f","Location":"3b"},"ORDER":["Day ASC","Location DESC"]}
given Base64-string:
eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0=
First I'm decoding the example-string
let str = "eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0="
let data = NSData(base64EncodedString: str, options: NSDataBase64DecodingOptions(rawValue: 0))
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
} catch let error {
print(error)
}
//"result" is ["WHERE": ["Class": "%3f", "Location": "3b"], "ORDER": ["Day ASC", "Location DESC"]]
Below I'm trying to reproduce the string from above
var array = [String : AnyObject]()
var arrayPartA = [String : String]()
arrayPartA["Class"] = "%3f"
arrayPartA["Location"] = "3b"
array["ORDER"] = ["Day ASC", "Location DESC"]
array["WHERE"] = arrayPartA
array //The playground says that "array" is ["ORDER": ["Day ASC", "Location DESC"], "WHERE": ["Class": "%3f", "Location": "3b"]]
//"ORDER" and "WHERE" are switched but I don't get them to be at the right position
let utf8str2: NSData = String(array).dataUsingEncoding(NSUTF8StringEncoding)!
let encodedStr = utf8str2.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
//Here "encodedStr" is WyJPUkRFUiI6ICgKICAgICJEYXkgQVNDIiwKICAgICJMb2NhdGlvbiBERVNDIgopLCAiV0hFUkUiOiB7CiAgICBDbGFzcyA9ICIlM2YiOwogICAgTG9jYXRpb24gPSAzYjsKfV0=
//but it should be eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0=
I would be glad if someone could explain to me what I'm doing wrong and how I can reproduce the given Base64-string.
Since I'm new to this website I apologize in advance for wrong layout or other possible conventions I don't know.
Could you try this please? Is this what you wanted to do? It should convert a Dictionary to base64 String
func jsonToBaseString (yourJSON: [String: String]) -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: yourJSON, options: JSONSerialization.WritingOptions.prettyPrinted)
return
jsonData.base64EncodedString(options: .endLineWithCarriageReturn)
} catch {
return nil
}
}
Dictionary is Swifts JSON representation...
Two important things to understand:
What you are calling an array is not an array, it's a JSON dictionary (containing an array for the ORDER key).
Be careful not to confuse the syntax of arrays and dictionaries between Swift and JSON.
In Swift, an array: [0, 1], a dictionary: ["a":0, "b":1].
In JSON, an array: [0, 1], a dictionary: {"a":0, "b":1}.
A Swift dictionary is an unordered collection. There's no "position" for key-value pairs.
You'll need to change several things:
Your input string (not serialized) is not an array, but a JSON object.
Try constructing your string with a proper JSON library, such as SwiftyJSON.
String(array) is not enough to consistently convert your objects to strings. You should use a JSON serializer (such as SwiftyJSON json.rawString()).
let follow recommendation to use some json serialization, but take in account that
{
"alfa": 1,
"beta": true
}
and
{"beta":true,"alfa":1}
represents in JSON notation the same object even though their string representation ( doesn't matter if base64 encoded or not ) are different.
I'm using Parse and I have an array of PFObjects called "scorecardData". Each PFObject has a "score" property that is of type Int. I'm trying to sort my array by "score" but I'm getting the following error: "Binary operator '<' cannot be applied to two 'AnyObject?' operands". I'm not sure what I'm doing wrong here. I also tried down casting the objectForKey("score") as! Int but its not letting me do this. Any suggestions? Thanks in advance.
var scorecardData = [PFObject]()
scorecardData.sortInPlace({$0.objectForKey("score") < $1.objectForKey("score")})
You declared scorecardData variable as Array of PFObject. Why are you trying access PFObject property using objectForKey: reserved? Anyway I am not parse expert. But if you declared your array as [PFObject] you can use:
scorecardData.sortInPlace({$0.score < $1.score})
But this won't work unless you subclass PFObject for a more native object-oriented class structure. If you do that remember also to specify:
var scorecardData = [YOUR_NEW_CLASS]()
I strongly recommend subclassing PFObject to make use of all swift type-safe goodies.
But if you want to keep your data structure you can use:
scorecardData.sortInPlace({($0["score"] as! Int) < ($1["score"] as! Int)})
Keep in mind that it's dangerous, and in future avoid it.
If you want to Sort your array of PFOject... You can do this
extension Array where Element:PFObject {
func sort() -> [PFObject] {
return sort { (first, second) -> Bool in
let firstDate = first.objectForKey("time") as! NSDate//objectForKey(Constants.Parse.Fields.User.fullName) as? String
let secondDate = second.objectForKey("time") as! NSDate//objectForKey(Constants.Parse.Fields.User.fullName) as? String
return firstDate.compare(secondDate) == .OrderedAscending
}
}
}
Have you tried doing this?
var query = PFQuery(className:"ScoreCard")
// Sorts the results in ascending order by the score field
query.orderByDescending("score")
query.findObjectsInBackgroundWithBlock {
i'm updating my app to Swift 2.. lots of errors uff.. anyway i'm trying to read a store array in NSuserDefaults, in swift 1 worked but now i get nil error with EXC_Breakdown. i don't know how to fix that...
this is how i read it:
var DescriptionArray = save.objectForKey("NewsDescriptions")! as! NSArray
this i how i save it (Description is the array):
var SaveDescription = save.setObject(Description, forKey: "NewsDescriptions")
save.synchronize()
Here is an example of how you can store data into NSUserDefault in Swift 2.0. It is very similar to Objective-C concept, only different syntax.
Initialize your NSUserDefault Variable:
let userDefaults = NSUserDefaults.standardUserDefaults()
Initialize what type of data to save: In your case you used objectForKey, even though that should work, it's better to be more specific about your code.
var DescriptionArray = userDefaults.arrayForKey("NewsDescriptions")
Save your data:
userDefaults.setObject(Description, forKey: "NewsDescriptions")
Then you can synchronize to process the saving faster.
userDefaults.synchronize()
Here is an example with Swift 2:
func saveArray(value: NSArray) {
NSUserDefaults.standardUserDefaults().setObject(value, forKey:"NewsDescriptions")
NSUserDefaults.standardUserDefaults().synchronize()
}
func readArray() -> NSArray {
return NSUserDefaults.standardUserDefaults().arrayForKey("NewsDescriptions")!
}