I got this error on Crashlytics this morning and I can't firgure out what the problem is. It would be awesome to get your opinions about it. I thInk it's most likely a multi threading issue. But I'm not able to pin point exactly what it is.
EDIT: I dug a little deeper and here's the code that's failing:
Also, I've figured out that the error is:
Could not cast value of type '__NSSingleObjectArrayI' (0x1aa60bca0) to 'NSMutableArray' (0x1aa60bd90).
2016-09-22 08:29:34.136764 GrabbnGo[4204:822290] Could not cast value of type '__NSSingleObjectArrayI' (0x1aa60bca0) to 'NSMutableArray' (0x1aa60bd90).
This was working perfectly all this while and it's suddenly causing problems and the app is already on the store :/
json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as? [String: AnyObject]
let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(str)
let OrderDictionary = json as NSDictionary
let result = OrderDictionary.objectForKey("result") as! NSMutableArray
OK, this sort of has a unique answer. Basically, you're misusing NSJSONSerialization, and it's a time-bomb bug that eventually bit you.
According to the documentation:
https://developer.apple.com/reference/foundation/jsonserialization
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
This is a very simple and clear sentence. You should respect it. It says nothing about NSMutableArray, only NSArray. The JSON parser is using whatever compatible (subclass) object for the NSArray that it so chooses. If there's only one item in the array, it appears that the internal type __NSSingleObjectArray is a lot more efficient, probably both in speed and memory.
There is almost certainly a change on the server (or customer behavior) such that result now (often? sometimes? always?) has only 1 item in it, so the JSON parser made a different choice that you're not supposed to care about.
All you need to do is change it to NSArray and construct an NSMutableArray from it if you really need:
let myJSONParsedArray: NSArray = ...
let myMutableArray = NSMutableArray(myJSONParsedArray)
But first learn about why force unwrapping is so dangerous, especially in a network code environment, when you can't trust any data at all, regarding type and value and maliciousness, ever!!
Related
I try to create a function for querying the Facebook database. Unfortunately, the syntax changed with the last version of swift. Maybe someone can post me the solution ?
Thx.
Func donneesFB
It's a lot easier to help you if you post your code as text instead of in an image.
Two things that will likely help you out here:
First, cast your result to the type of dictionary you are expecting before trying to access it:
guard let resultDict = result as? [String:Any] else { return }
You should now be able to use it like you tried to:
let nom = resultDict["name"] as? String
Secondly, for the error on your first line, simply get rid of the argument labels, nom, prenom and so on, leaving just the types.
I have created an iOS app using Swift and everything is working fine and dandy on the simulator. I get no errors or crashes at all, but when I submit my app to put up on the app store Apple rejects it and lets me know that it crashes when the user makes a selection. I cannot recreate this error/crash. I took the crash logs and symbolicated them. This line of code came up as the culprit for the crashes:
linksToPass = getLinks(season) as [String:[String]]
This line is trying to store the resulting Dictionary from the getLinks() function I created. It for sure is getting a dictionary and if there is no dictionary to send back I create a dictionary which has error information in it, so it is for sure returning a dictionary in that format no matter what. Seeing as I cannot recreate the crash, I am just trying to error check this line of code in any way possible so it does't crash when I resubmit to Apple.
I tried checking if the resulting dictionary was nil like so:
if(getLinks(seasons) != nil){
linksToPass = getLinks(season) as [String:[String]]
}
This is not valid though, and XCode lets me know that UInt8 is not compatible with NSDictionary or something of that nature.
I then fixed that line and changed it to this:
if(getLinks(seasons) != ["":[""]]){
linksToPass = getLinks(season) as [String:[String]]
}
I am just not sure if this is even a good way to check for errors. I was wondering if there were any suggestions on how I may go about making sure this line does not fail and result in a crash. Thank you very much.
EDIT:
Here is my getLinks() function if that helps add more info to the problem:
var season = ""
let hymn_links = Hymn_Links()
func getLinks (nameofseason:String) -> NSDictionary
{
switch (nameofseason)
{
default:
return ["Maps Not Found": []]
}
}
EDIT #2:
This is my updated getLinks() function with the use of optionals.
func getLinks (nameofseason:String) -> NSDictionary?
{
switch (nameofseason)
{
default:
return nil
}
}
Also in my statement of linksToPass I changed it to:
if let links = getLinks(season) as? [String:[String]]
{
linksToPass = links
hymnnames = [String] (linksToPass.keys)
}
There are some known issues with the Swift optimiser. Some people have resorted to shipping with debug builds.
My suggestion would be to test with an optimised build to see if you can reproduce it. You can then try shipping a debug build to the App store.
General Code Comments
Why are you returning an NSDictionary rather than a Swift dictionary anyway? Without knowing the contents and creation method for your hymn_links object I can't be sure how good it is.
I would avoid as casts until Swift 1.2 and stick to using as? and then handling the nil case. At least in your "Edit 2" a nil will cause a crash as nil cannot be cast to [String:[String]] although [String:[String]]? should be possible.
Can you guarantee that all of the items returned by the switch statement will never under any circumstances be nil? If not getLinks should return an Optional.
Note that is is virtually impossible for getLinks to know that one of the items will never be nil and in Swift un-handed nils are a crash waiting to happen. Unless all these methods correctly handle nil.
Return an Optional and handle that in the statement that calls getLinks.
Languages handle nils differently, Objective-C handles them rather well, Java and Swift by crashing. But Swift has a mechanism to handle nils without crashing: Optionals, use it.
I seem to be having a problem trying to create an NSDictionary in Swift using one of the convenience intializers. My confusion though lies in the fact that the error says my function signature is wrong, yet I'm using the function signature that XCode autocompleted for me.
My Code:
var query = NSDictionary(objects: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData], forKeys: [kSecClassGenericPassword, "healthBIT.lastSync", key, true])
The XCode provided signature:
var query = NSDictionary(objects: <#[AnyObject]#>, forKeys: <#[AnyObject]#>)
The error when compiling is: Extra argument 'forKeys' in call
What am I missing here? Am I just too sleep deprived to see the obvious? Or is it just a stupid mistake derived from my relative inexperience with Swift?
PS: I am trying to use NSDictionary here instead of a normal Swift dict because Swift dicts can't store mixed types, and I need to pass this to the underlying C based Keychain API.
After a discussion in chat, it turned out the problem is about the key variable referenced from the code sample provided in the question, which comes from a for loop:
for key in lastSync {
...
}
the error is that key is a (key, value) tuple, and that's causing issues when using it in a NSDictionary (objc types cannot handle swift specific features, such as generics, tuples, etc.).
The problem is solved by expanding the tuple accordingly:
for (key, value) in lastSync {
...
}
or, if value is not used:
for (key, _) in lastSync {
...
}
I'm trying to read the Linkedin response in swift.
My object is something like this ["positions":["values":["data1","data2","data3"]]]
if let positions: NSDictionary = info["positions"] as NSDictionary!{
if let positionsInfo: [NSDictionary] = positions["values"] as? [NSDictionary]{
for position : NSDictionary! in positionsInfo {
dosomething(position, person:usr)
}
}
}
If I do a StepOver line by line it works correctly. But if I run it i'll get a EXC_BAD_ADDRESS(code=1,address=0x7966b04) I enabled Zombie objects and ran it on Instruments. I'm pretty sure this is the code which is causing the problem. But not sure what is wrong with it.
The moment you used ! you opened yourself up for crashes if there were any problem. You must use as? to make sure that the data is actually what you think it is.
There are many blog posts out there on how to safely parse JSON into Swift data structures. It's now almost a rite of passage for Swift bloggers.
http://robots.thoughtbot.com/efficient-json-in-swift-with-functional-concepts-and-generics
http://chris.eidhof.nl/posts/json-parsing-in-swift.html
https://github.com/owensd/json-swift
https://github.com/lingoer/SwiftyJSON
Of course the many packages: https://github.com/search?q=%5Bswift%5D+json
http://robnapier.net/functional-wish-fulfillment - My own version on top of all the others
What I am trying to do is convert a document to an dictionary and then iterate that dictionary to see what's inside, but I am having the following problem when trying to convert the document.
I have the following code:
CBLDocument *document = row.value;
NSDictionary *dict = document.properties;
the xCode is always complaining "[__NSCFDictionary currentRevision]: unrecognized selector sent to instance 0x90c4150" when running to the second statement.
I have also tried NSDictionary *dict = document.currentRevision.properties;
It's not working either.
Could anyone help me with that?
OK, it turns out row.value is not a document(is actually a dictionary), but nobody tells me that when I emit(#[somekey], doc); The doc (which is the value) is actually a dictionary instead of a document.
But weird though the compiler did not complain when assigning the dictionary to a CBLDocument.