App crashing on checking count NSMutableArray - ios

the app crashes on checking for count of NSMutablearray if it is nil,i am not getting how to handle it, i am new to ios
let userDefaults: UserDefaults? = UserDefaults.standard
let array = userDefaults?.object(forKey: "purchaselist") as? NSMutableArray
for i in 0..<array!.count {
}

You should check for nil also,
if let array = userDefaults?.object(forKey: "purchaselist") as? [Any], !array.isEmpty {
//Your code goes here
}
You can do this way also,
if let array = userDefaults?.object(forKey: "purchaselist") as? NSMutableArray {
if array.count != 0 {
//Your code goes here
} else {
//array count zero
}
} else {
//Your array is nil
}
FYI. Code is not tested, it is just information.

Related

[NSNull length]: unrecognized selector sent to instance 0x10f8c6fc0' swift 4 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.

Swift - Append to NSMutableDictionary

I am trying to append to an NSMutableDictionary with the following code:
let RSVPDirectory = NSMutableDictionary()
for i in 0..<self.RSVPs.count {
var tmp = self.RSVPs[i]
var firstLetter = String()
if(tmp["lastname"] is NSNull)
{
firstLetter = ((tmp["email"] as? NSString)?.substring(to: 1).uppercased())!
}
else
{
firstLetter = ((tmp["lastname"] as? NSString)?.substring(to: 1).uppercased())!
}
if RSVPDirectory[firstLetter] == nil {
RSVPDirectory[firstLetter] = [AnyHashable]()
}
RSVPDirectory[firstLetter] = tmp
}
My problem with this is that I am expecting multiple tmp inside RSVPDirectory[firstLetter] but it only adds the first one as if its overriding the previous tmp
How do I append to NSMutableDictionary in swift, I know in objective-c you can do this:
[[RSVPDirectory objectForKey:firstLetter] addObject:tmp];
What would be the equivalent to that in swift?
Try the below code in a playground you will see the output, hope this gives you an idea.
func upperCaseFirstLetter(_ str: String) -> String {
guard let first = str.first else { return "" }
return "\(first)".uppercased()
}
var RSVPs = [[String:String]]()
var RSVPDirectory = [String: [[String:String]]]()
//Test Data
var str = ["email":"test1#c.com"]
RSVPs.append(str)
str = ["lastname":"Atest2"]
RSVPs.append(str)
for i in 0..<RSVPs.count {
var tmp = RSVPs[i]
var firstLetter = ""
if(tmp["lastname"] == nil) {
firstLetter = upperCaseFirstLetter(tmp["email"]!)
} else {
firstLetter = upperCaseFirstLetter(tmp["lastname"]!)
}
if RSVPDirectory[firstLetter] == nil {
RSVPDirectory[firstLetter] = [[String:String]]()
}
RSVPDirectory[firstLetter]?.append(tmp)
}
print(RSVPDirectory)
This is the native Swift version of your Objective-C-ish code.
It uses the Dictionary(grouping API of Swift 4
let RSVPDirectory = Dictionary(grouping: RSVPs) { (dictionary) -> String in
if let lastName = dictionary["lastname"] as? String {
return String(lastName.prefix(1).uppercased())
} else if let email = dictionary["email"] as? String {
return String(email.prefix(1).uppercased())
} else {
return "🚫"
}
}
Yes you are actually replacing the RSVPDirectory[firstLetter], overriding it every time with new tmp.
What you are looking for is this:
//RSVPDirectory[firstLetter] = tmp //Replace this line with below code
let tempArray = RSVPDirectory[firstLetter] as? [AnyHashable]
tempArray?.append(tmp)
RSVPDirectory[firstLetter] = tmpArray
Here I have used a tempArray because we want to mutate the array. Accessing it directly and trying to append new value will in-turn try to mutate an immutable value. So first I have got the array in the tempArray and then after mutating the array I swapped it back in the dictionary with updated values.

swift UserDefaults return nil as NSMutableArray

I have multi line texts and i save them UserDefaults. When i want to get the text sometimes return nil. But there is a text in it. How can i do that the nil does not return?
var savedReports: NSMutableArray = NSMutableArray()
if let sR = defaults.object(forKey: "savedReports") as? NSMutableArray {
savedReports = sR.mutableCopy() as! NSMutableArray
}
The UserDefaults API will always return immutable arrays. You want:
var savedReports: NSMutableArray = NSMutableArray()
if let sR = defaults.object(forKey: "savedReports") as? NSArray {
savedReports = sR.mutableCopy()
}

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

Resources