Could not cast value of type '__NSCFNumber' (0x10e59f3c0) to 'NSString' (0x10dba7ad8) swift 3 - xcode

I've been tying to figure out this one for a few days now... Here is my original code:
if let ratingDic = dictionary["rating"] as? [String: Any],
let ratingId = ratingDic["id"] {
searchResult.ratingID = ratingId as! String
}
Here is my api:
"amount" = "50.00";
"rating" = {
"name" = "Platinum";
"id" = 5
I'm pretty sure I need to use "valueForKey" so here is my updated code:
if let ratingDic = dictionary["rating"] as? [String: Any],
//let ratingId = ratingDic["id"] {
let ratingId = [ratingDic.valueForKey("id")!] {
searchResult.ratingID = ratingId as! Number
}
However now I receive the "Value for type String:Any has no member "valueForKey"

Never mind, I was forgetting to change the actual variable to a "Double" or number
var ratingID = 0.0
instead of
var ratingID = ""
and the code now reads
if let ratingDic = dictionary["rating"] as? [String: Any],
let ratingId = ratingDic["id"] {
searchResult.ratingID = ratingId as! Double
}

Related

Knowing when to use a Double, String or Int when casting an Array from an API?

I am trying to cast multiple Arrays from a weather API. I was able to get the 5 day highs using a Double, then I was able to match them with the days of the week using a String.
Now I am trying to pull the the 5 days lows and the weather Icons associated to the day and no matter what I use Double, String or Int there is no data coming back.
Here is a part of my code that is working.
var temperatureArray: Array<Double> = Array()
var dateArray: Array<String> = Array()
var iconArray: Array<String> = Array()
var dayNumber = 0
var readingNumber = 0
if let jsonObj = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary {
if let mainArray = jsonObj!.value(forKey: "list") as? NSArray {
for dict in mainArray {
if let mainDictionary = (dict as! NSDictionary).value(forKey: "main") as? NSDictionary {
if let temperature = mainDictionary.value(forKey: "temp_max") as? Double {
if readingNumber == 0 {
temperatureArray.append(temperature)
} else if temperature > temperatureArray[dayNumber] {
temperatureArray[dayNumber] = temperature
}
} else {
print("Error: unable to find temperature in dictionary")
}
if let date = (dict as! NSDictionary).value(forKey: "dt_txt") as? String {
if readingNumber == 0 {
dateArray.append(date)
}
}
} else {
print("Error: unable to find main in dictionary")
}
if let icon = (dict as! NSDictionary).value(forKey: "icon") as? String {
if readingNumber == 0 {
iconArray.append(icon)
}
}
readingNumber += 1
if readingNumber == 8 {
readingNumber = 0
dayNumber += 1
}
}
I get no build errors, but cannot draw data for the icon array.
#Vadian, thank you!! I took me a while, but we were actually trying to break though 2 Array Strings to get to the "icon" key!! this is how I did it.
if let mainArray = jsonObj!.value(forKey: "list") as? NSArray {
for dict in mainArray {
if let weatherArray = (dict as AnyObject).value(forKey: "weather") as? NSArray {
if let weatherDictionary = weatherArray[0] as? NSDictionary {
if let icon = weatherDictionary.value(forKey: "icon") as? String {

swift 3 core data fetch results

i have a core data modal with the entity "Users"
There are two attributes "firstName" and "secondName"
this is actually my code to fetch the results:
var content:[String] = []
func RequestData() {
let appdelegate = NSApplication.shared().delegate as! AppDelegate
let context = appdelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Kunden")
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
if results.count > 0 {
for result in results as! [NSManagedObject] {
if let firstname = result.value(forKey: "firstname") as? String {
content.append(firstname)
}
if let secondname = result.value(forKey: "secondname") as? String {
content.append(secondname)
}
}
}
tbl_kunden.reloadData()
} catch {
print("ERROR")
}
}
this works fine.
Problem is. I dont belive that
var content:[String] = []
is the correctly variable to take the results.
Because the output of print(content) is:
["Max", "Mustermann", "Max2", "Mustermann2", "Max3", "Mustermann3"]
Which variable type will be the best for this situation?
i think the result should be something like this:
+ID
++Max
++Mustermann
+ID
++Max2
++Mustermann2
+ID
++Max3
++Mustermann3
You should create custom User objects that are subclasses of NSManagedObject.
https://developer.apple.com/reference/coredata/nsmanagedobject
But if you don't need custom logic, you could change your variable to a Int:[String] Dictionary:
var content:[Int: [String]] = [:]
And append the data like this:
if let id = result.value(forKey: "firstname") as? Int {
let firstName = result.value(forKey: "firstname") as? String ?? "Unknown"
let secondName = result.value(forKey: "secondname") as? String ?? "Unknown"
let user = [id: [firstName, lastName]]
print("Fetched user: \(user.debugDescription)")
}

fatal : Array index out of range

Every child has a pick up point location consists of latitude and longitude that i fetch from sqlite database. I have childIdArray which is array of childID's. I want to calculate the estimate time(ETA) from current location of their respective drivers location i fetch from getCurrentLocationOfRespectiveDrivers() method with pickUp point of children that i fetch from sqlite database in form of array of latitude and longitude.
but i get error
fatal error: Array index out of range
in getCurrentLocationOfRespectiveDrivers() method.
Any help would be highly appreciated.. thanks in advance
var etaArray : [String] = []
var estimatedTime : String?
var latitudeArray : [Double] = []
var longitudeArray : [Double] = []
override func viewDidLoad() {
super.viewDidLoad()
let rs = ModelManager.sharedInstance.fetchingPickUpAnnotationsArray(ChildDetailsVC.parentID)
latitudeArray = rs.latPickUp
longitudeArray = rs.longPickUp
print("pickUpLatitudeArray = \(latitudeArray)")
print("pickUpLongitudeArray = \(longitudeArray)")
let result = ModelManager.sharedInstance.fetchingChildren( ChildDetailsVC.parentID)
self.childNameArray = result.childNames
self.childImageArray = result.childImages
self.childIDArray = result.chidIDs
self.childDriverArray = result.childDrivers
getCurrentLocationOfRespectiveDrivers()
for (var i = 0; i < childIDArray.count; i++)
{
etaArray.append("")
}
}
func getCurrentLocationOfRespectiveDrivers()
{
for( var i = 0 ; i < latitudeArray.count ; i++)
{
let url:NSURL = NSURL(string:"http://development.ssntpl.com/gogo_app/api.php?action=getDriverCurrentLocation")!
let request = NSMutableURLRequest(URL:url)
request.HTTPMethod = "POST"
let post:NSString = "child_id=\(childIDArray)"
request.HTTPBody = post.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
if error != nil
{
print("error is \(error)")
return;
}
do
{
let myJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = myJSON
{
let Status = parseJSON["status"] as! Int
let Code = parseJSON["code"] as! Int
if (Status == 1 && Code == 200)
{
let Result = parseJSON["result"] as! NSArray
self.etaArray.removeAll()
//here i get the crash fatal error: Array index out of range
let latitudePickUp = self.latitudeArray[i]
let longitudePickUp = self.longitudeArray[i]
let CoordinatePickUp = CLLocation(latitude: latitudePickUp, longitude: longitudePickUp)
for res in Result
{
self.estimatedTime = ""
if (res["exists"] as! Int == 1)
{
let lastLatitude = res["latitude"] as! CLLocationDegrees
let lastLongitude = res["longitude"] as! CLLocationDegrees
let Location : CLLocation = CLLocation(latitude: lastLatitude, longitude: lastLongitude)
let meters:CLLocationDistance = Location.distanceFromLocation(CoordinatePickUp)
print(meters)
let ID = res["child_id"] as! String
let time = round(meters/40000 * 60)
self.estimatedTime = String(time)
self.etaArray.append(self.estimatedTime!)
}
else
{
self.etaArray.append("")
}
}
}
else
{
}
}
}
catch
{
print(error)
}
}
//executing the task
task.resume()
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}

Replacing NSNulls inside NSDictionary

this question is similar to Replace occurrences of NSNull in nested NSDictionary
In swift I am getting an error (I believe because of NSNull's) I don't really care if the NSNull becomes an empty string or a nil. I am just wanting to get the code to work.
I have a large data structure coming in from JSON as an NSDictionary. Then I am saving that to a temporary file. Here is the code:
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as! NSDictionary
let json = JSON(jsonResult)
if (json["errors"].array?.count > 0) {
println("could not load stuff")
} else {
println("retrieving the stuff")
let file = "file.txt"
let file_path = NSTemporaryDirectory() + file
let dict:NSDictionary = jsonResult
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
if dict.writeToFile(file_path, atomically: true) {
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
//--- need to handle the NSNull junk here
if let dict = readDict {
println("Temp file created, here are the contents: \(dict)")
} else {
println("!!!Failed to READ the dictionary data back from disk.")
}
}
else {
println("!!!Failed to WRITE the dictionary to disk.")
}
}
Here's an example of what jsonResult looks like
things = (
{
"one" = one;
two = "<null>";
"three" = three;
"four" = "<null>";
"five" = five;
"six" = "six-6";
seven = 7;
eight = eight;
nine = "<null>";
ten = "<null>";
eleven = "<null>";
"twelve" = "<null>";
},
UPDATE:
Problem: I have a very large amount of JSON (roughly 600kb as text) Within that JSON data there are nulls. The problem I was having is that when you NSJSONSerialization as NSDictionary, it converts the nulls into NSNull objects (it looks funky if you print this out because they appear as a string, this is wrong.
Solution: You need to have a "pruned" or "sanitized" dictionary. What this means is to throw out the key and value entirely. To do this, I added a sanitized_dict function. Here is the function:
func sanitize_dict(obj: AnyObject) -> AnyObject {
if obj.isKindOfClass(NSDictionary) {
var saveableObject = obj as! NSMutableDictionary
for (key, value) in obj as! NSDictionary {
if (value.isKindOfClass(NSNull)) {
//println("Removing NSNull for: \(key)")
saveableObject.removeObjectForKey(key)
}
if (value.isKindOfClass(NSArray)) {
let tmpArray: (AnyObject) = sanitize_dict(value as! NSArray)
saveableObject.setValue(tmpArray, forKey: key as! String)
}
if (value.isKindOfClass(NSDictionary)) {
let tmpDict: (AnyObject) = sanitize_dict(value as! NSDictionary)
saveableObject.setValue(tmpDict, forKey: key as! String)
}
}
return saveableObject
//--- because arrays are handled differently,
//--- you basically need to do the same thing, but for an array
//--- if the object is an array
} else if obj.isKindOfClass(NSArray) {
var saveableObject = [AnyObject]()
for (index, ele) in enumerate(obj as! NSArray) {
if (ele.isKindOfClass(NSNull)) {
// simply don't add element to saveableobject and we're good
}
if (ele.isKindOfClass(NSArray)) {
let tmpArray: (AnyObject) = sanitize_dict(ele as! NSArray)
saveableObject.append(tmpArray)
}
if (ele.isKindOfClass(NSDictionary)) {
let tmpDict: (AnyObject) = sanitize_dict(ele as! NSDictionary)
saveableObject.append(tmpDict)
}
}
return saveableObject
}
// this shouldn't happen, but makes code work
var saveableObject = [AnyObject]()
return saveableObject
}
So your other code needs to call that function, it should look something like this:
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as! NSDictionary
//--- right now jsonResult is not actual json, and actually has the NSNulls
//--- get that result into the sanitized function above
let saveableDict: (AnyObject) = self.sanitize_dict(jsonResult)
let json = JSON(saveableDict)
if (json["errors"].array?.count > 0) {
println("!!!Failed to load.")
} else {
println("Load json successful. Attempting to save file...")
//--- set up basic structure for reading/writing temp file
let file = "file.txt"
let file_path = NSTemporaryDirectory() + file
let dict:NSDictionary = jsonResult
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
if dict.writeToFile(file_path, atomically: true) {
let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)
if let dict = readDict {
println("Temp file created, here are the contents: \(dict)")
} else {
println("!!!Failed to READ the dictionary data back from disk.")
}
}
else {
println("!!!Failed to WRITE the dictionary to disk.")
}
}
Hope this helps somebody out there with a big JSON dataset and nulls. It is all about that sanitize function!

Signal SIGABRT in Swift using NSuserdefaults

I'm building a swift game and a need to set up a class. My code works for all the elements in my class, but not for this.
func saveInformationMember(){
var MembersDefaultName = NSUserDefaults.standardUserDefaults()
MembersDefaultName.setValue(globalCurrentMembers, forKey: "globalCurrentMembersData")
MembersDefaultName.synchronize()
}
GlobalCurrentMembers is an array of Member which looks like that:
class Member {
var image = String ()
var name = String ()
var progression = Int()
var round = Int()
var level = Int()
var imageProgression = [UIButton]()
func Init(){
image = "default.png"
name = "default"
progression = 0
round = 0
level = 0
}
To save your class this way, Member needs to conform to the NSCoding protocol.
Thx to Aaron Brager for is response. This is the response :
func saveInformationMember(){
let data = NSKeyedArchiver.archivedDataWithRootObject(globalCurrentMembers)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "member")}
func loadInformationMember(){
if let data = NSUserDefaults.standardUserDefaults().objectForKey("member") as? NSData {
globalCurrentMembers = NSKeyedUnarchiver.unarchiveObjectWithData(data) as [Member]
}
And my class:
class Member : NSObject, NSCoding {
var image = String ()
var name = String ()
var progression = Int()
var round = Int()
var level = Int()
var imageProgression = [UIButton]()
func initiation(){
image = "default.png"
name = "default"
progression = 0
round = 0
level = 0
}
required convenience init(coder decoder: NSCoder) {
self.init()
self.image = decoder.decodeObjectForKey("image") as String!
self.name = decoder.decodeObjectForKey("name") as String!
self.progression = decoder.decodeIntegerForKey("progression") as Int!
self.round = decoder.decodeIntegerForKey("round") as Int!
self.level = decoder.decodeIntegerForKey("level") as Int!
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(self.image, forKey: "image")
coder.encodeObject(self.name, forKey: "name")
coder.encodeInt(Int32(self.progression), forKey: "progression")
coder.encodeInt(Int32(self.round), forKey: "round")
coder.encodeInt(Int32(self.level), forKey: "level")
}}

Resources