[NSNull length]: unrecognized selector sent to instance 0x10f8c6fc0' swift 4 iOS - ios

I am fetching data from the model in this way
if let birthdate = personInfo?.str_Birthdate {
cell.dobTF.text = birthdate
}
But app crash and return this error
'-[NSNull length]: unrecognized selector sent to instance 0x10f8c6fc0'

What you are getting here is NSNull. It is an object representing null in context of objective-C arrays and dictionaries. Specifically in JSONs it distinguishes between receiving field (null) instead of not receiving a field at all. In your case I assume this value is force-unwrapped as a string so the error is a bit late. Please try the following:
if let dateObject = personInfo?.str_Birthdate {
if let nullObject = dateObject as? NSNull {
// A field was returned but is (null)
} else if let stringObject = dateObject as? String {
cell.dobTF.text = stringObject
} else {
// Unknown object
}
} else {
// This field is missing
}
You can actually just convert all NSNull instances to nil using something like:
func removeNSNullInstancesFrom(_ item: Any?) -> Any? {
guard let item = item else { return nil }
if let _ = item as? NSNull {
return nil
} else if let array = item as? [Any] {
return array.compactMap { removeNSNullInstancesFrom($0) }
} else if let dictionary = item as? [String: Any] {
var newDict: [String: Any] = [String: Any]()
dictionary.forEach { item in
guard let value = removeNSNullInstancesFrom(item.value) else { return }
newDict[item.key] = value
}
return newDict
} else {
return item
}
}
You can use this on the whole response object or a specific item. In your case you can do: cell.dobTF.text = removeNSNullInstancesFrom(birthdate).
But this method should in general recursively remove all NSNull instances from fields, arrays and dictionaries which are standard for JSON.

Related

I want to change my label colour according to text in response from server

I am using For loop in CellForRowat Indexpath to change colour but it showing me error how can I resolve it. and I put the correct key value
Error(Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[_SwiftValue objectForKey:]:
unrecognized selector sent to instance 0x6040000f6680'
for all in arrayForType!
{
let type = (all as AnyObject).object(forKey: "type") as! String
print(type)
if type == "Send"
{
cell.lblForSend.backgroundColor = UIColor.red
}
else
{
cell.lblForSend.backgroundColor = UIColor.green
}
}
Your issue is that AnyObject don't have .object(forKey: #"") method, objectForKey method is a method of NSDictionary that is your crash reason
https://developer.apple.com/documentation/foundation/nsdictionary/1414347-objectforkey
The error seems to be in this line:
let type = (all as AnyObject).object(forKey: "type") as! String
You're treating all as AnyObject (which is redundant, by the way), but the method you call on it - object(forKey: String) - is a method of NSDictionary class
instead, try
guard let array = arrayForType else { return }
for all in array
{
guard let dict = all as? NSDictionary else { continue }
guard let type = dict.object(forKey: "type") as? String else { continue }
print(type)
if type == "Send"
{
cell.lblForSend.backgroundColor = UIColor.red
}
else
{
cell.lblForSend.backgroundColor = UIColor.green
}
}
Also, avoid force-unwrapping optionals (the ! operator), although this was not the cause of crash in your case
I have resolvedly issue and it is correct way to do it.
let type = (arrayForType[indexPath.row] as AnyObject).object(forKey: "type") as! String
print(type)
if type == "Send"
{
cell.lblForSend.backgroundColor = UIColor.red
}
else
{
cell.lblForSend.backgroundColor = UIColor.green
}
you should always try to avoid implicitly unwrap, especially when you work data fetched from server. try to use Optional Binding to achieve more safecity. just like that
guard let arrayForType = arrayForType as? [NSDictionary] else { return }
for all in arrayForType {
if let type = all.object(forKey: "type") as? String, type == "Send" {
cell.lblForSend.backgroundColor = .red
} else {
cell.lblForSend.backgroundColor = .green
}
}

Mapping to Realm Result to NSDictionary Error

I have been using this extension to successfully map my Realm Results to NSDictionary:
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
return mutabledic
}
}
But I am now trying to map :
let allObjectLists = realm.objects(UseItemList.self)
let firstObject = allObjectLists[0].valueForKey("useItems")
let toDict = firstObject?.toDictionary() //error here
How do I fix this, there must be a way to map allObjectLists[0].valueForKey("useItems") to a Dictionary
Here is the Error I get:
2016-11-10 11:45:09.056 CPS Stocker[6187:167500] -[_TtGC10RealmSwift4ListC11CPS_Stocker7UseItem_ toDictionary]: unrecognized selector sent to instance 0x7fa7f3a49650
2016-11-10 11:45:09.253 CPS Stocker[6187:167500] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_TtGC10RealmSwift4ListC11CPS_Stocker7UseItem_ toDictionary]: unrecognized selector sent to instance 0x7fa7f3a49650'
And here is my UseItemList Object class:
class UseItemList: Object {
dynamic var dateCreated = NSDate()
dynamic var locationUnique = Int()
dynamic var MainActivityReference1 = ""
dynamic var MainActivityReference2 = ""
let useItems = List<UseItem>()
}
Here is how I fixed it :
let firstObjectInList = allObjectLists.first!
let useItemsInFirstObject = firstObjectInList.useItems
for firstUseItem in useItemsInFirstObject {
let dit = firstUseItem.toDictionary()
usedObjectDictionaries.append(dit)
}
You're not accessing an Object there.
That line of code let firstObject = allObjectLists[0].valueForKey("useItems") is pulling out the useItems object, which is a List object. This is why it's reporting there's no method named toDictionary() available for it.
If you're trying to get the first object in useItems to generate a dictionary off that, it should be:
let allObjectLists = realm.objects(UseItemList.self) // Get all 'UseItemList' objects from Realm as a `Results` object
let firstObjectInList = allObjectLists.first! // Get the first UseItemList object from the 'Results' object
let useItemsInFirstObject = firstObjectInList.useItems // Access the 'useItems' List object in the first object
let firstUseItem = useItems.first! // Access the first item from the 'useItems' List object
let toDict = firstItem.toDictionary() // Convert the first item into an array
Obviously you can condense this down into one line of code, but you need to make sure you're accessing all of the elements in the right order or else you won't get to a proper Object at the end. :)

How to detect an empty Dictionary without crashing in Swift 2.0?

I am trying to detect if the dictionary coming from API is empty or has values but whenever i am trying to do Dict.count it crashes.
if let personalInfo = self.scanResult?.fields { // personalInfo has 0 values but not nil
let image = NSData(base64EncodedString: (personalInfo["Photo"] as? String)!, options: NSDataBase64DecodingOptions(rawValue: 0)) // Crashes
}
I also tried isEmpty and it crashes there as well.
You should unwrap personalInfo["Photo"] before trying to use it. This way you can ensure you're not trying to instantiate NSData without a value for the Photo key being present
if let personalInfo = self.scanResult?.fields{
if let encodedString = personalInfo["Photo"] as? String{
let image = NSData(base64EncodedString: encodedString,options: NSDataBase64DecodingOptions(rawValue:0))
}
}
I think the simplest solution is to check dictionary keys count is greater than 0. For example:
let dictionary: Dictionary<String, AnyObject> = Dictionary()
if dictionary.keys.count > 0 {
// This mean dictionary has values.
}
The problem was that the self.scanResult.fields was coming out as NSNull. so i found these 3 methods which resolves the problem.
func isNotNull(object:AnyObject?) -> Bool {
guard let object = object else {
return false
}
return (isNotNSNull(object) && isNotStringNull(object))
}
func isNotNSNull(object:AnyObject) -> Bool {
return object.classForCoder != NSNull.classForCoder()
}
func isNotStringNull(object:AnyObject) -> Bool {
if let object = object as? String where object.uppercaseString == "NULL" {
return false
}
return true
}
And i just call like this :
if self.isNotNSNull((self.scanResult?.fields)!
{
}
You can use the "count" of dictionary. See the code.
if let personalInfo = self.scanResult?.fields {
if personalInfo.count > 0 {
if let base64ImageString = personalInfo["Photo"] as? String {
if let image = NSData(base64EncodedString: base64ImageString, options: NSDataBase64DecodingOptions(rawValue: 0)) {
// do your stuff with image
}
}
}
}

Check NSArray contain NSDictionary key in Swift?

I have array of NSDictionary and i want check particular NSDictionary "key" present in NSArray or not.
I tried
if let val = dict["key"] {
if let x = val {
println(x)
} else {
println("value is nil")
}
} else {
println("key is not present in dict")
}
and
let arrayOfKeys = dictionary.allKeys
if (arrayOfKeys.containsObject(yourKey)) {
}
else {
}
but this is for individual array object. Also
if ([[dictionary allKeys] containsObject:key]) {
// contains key
}
This method for individual NSDictionary not for NSArray.
Also
if readArray.contains(["A":1]) { ALToastView.toastInView(UIApplication.sharedApplication().keyWindow, withText: "Already added")
}else{
readArray.append(["A":0]
}
This code will add again same key in array if change value for key "A"
Ex. My array contain dictionary ["A":1] and i want to check key "A" is present or not?
How do i check any key present in Array? Do i need to iterate array? Thanks in advance.
Refer following example :
var array = [[String:Any]]()
array.append(["key1":"value1"])
array.append(["key2":"value2"])
array.append(["key3":"value3"])
array.append(["key4":"value4"])
array.append(["key5":"value5"])
let key = "key5"
if let index = (array.indexOf { (dict) -> Bool in
dict[key] != nil
})
{
print("Key Found at = \(index) ")
} else {
print("Key not Found")
}
You can use this method. Basically you iterate thru the array of dict getting a tuple of its index and dict and if the dict contains the key you store the index in an array.
let arrayOfDict = [
["key1":"value1", "key2":"value2"],
["key3":"value3", "key4":"value4", "key5":"value5"],
["key6":"value6", "key7":"value7", "key8":"value8"],
["key6":"value6", "key7":"value7", "key8":"value8"]
];
let keyToCheck = "key6"
var foundIndex = [Int]()
for (index, dict) in arrayOfDict.enumerate()
{
if let item = dict[keyToCheck] {
foundIndex.append(index)
}
}
if foundIndex.count > 0 {
print("Found at \(foundIndex)")
} else {
print ("not found")
}
You can also use this method if you want to get the dictionaries that contains the keys along with the index.
let newArray = arrayOfDict.enumerate().filter { (tuple:(index: Int, element: Dictionary<String, String>)) -> Bool in
if tuple.element.keys.contains(keyToCheck) {
return true
} else {
return false
}
}
The newArray will be an array of tuples of type (Int:[String:String]) wherein the tuple.0 will be the index and tuple.1 will be the dictionary

Type 'String' does not conform to protocol 'NSCopying' error when downcast AnyObject to String

I'm tring to parse a JSON format like this:
{
"key_1" : {
"key_2" : "value"
}
}
and then assign "value" to a variable.
Here is my code:
var variableShouldBeAssigned: String
if let x = (jsonResult["key_1"]? as? NSDictionary) {
if let y = (x["key_2"]? as? String) {
variableShouldBeAssigned = y
}
}
However, an error occurs when I try to downcast from x["key_2"]? to a String, but it's fine to downcast from jsonResult["key_1"]? to an NSDictionary.
I can solve the error by using x["key_2"] to replace x["key_2"]?, but I don't really know why it only works for jsonResult["key_1"]?.
Can anybody tell me the reason?
String does not conform to NSCopying, but surely NSString does!
Also, going from NSString to String is instantaneously implied...
So I would say try something like this... Change String to NSString
here is a sample, assuming that you handle the jsonResult as a NSDictionary...
func giveDictionary(jsonResult:NSDictionary) -> String?
{
if let x = (jsonResult["key_1"]? as? NSDictionary)
{
if let y = (x["key_2"]? as? NSString)
{
return y
}
}
return nil
}
You can simplify all your type checking by using a Swift dictionary at the beginning:
var variableShouldBeAssigned: String
if let dict = jsonResult as? [String:[String:String]] {
if let key1Dict = dict["key_1"] {
if let value = key1Dict["key_2"] {
variableShouldBeAssigned = value
}
}
}
In fact, you can even combine the two last if statements:
var variableShouldBeAssigned: String
if let dict = jsonResult as? [String:[String:String]] {
if let value = dict["key_1"]?["key_2"] {
variableShouldBeAssigned = value
}
}
In general, you should using Swift Dictionaries instead of NSDictionary

Resources