swift UserDefaults return nil as NSMutableArray - ios

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()
}

Related

App crashing on checking count NSMutableArray

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.

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.

Create an Array of Objects with Firebase Async Dictionary Download (Swift)

I'm new to Swift. I have been having trouble downloading Firebase dictionaries and turning them into an array of objects.
What am I doing wrong with the syntax below? I've spent the last two days unsuccessfully trying to figure this out. The following gives me an index out of range error. Is this because the Firebase Dictionary hasn't finished downloading yet or is my for in loop sytax flawed? Perhaps both? Thanks.
// Array of Location Objects
var locationsArray:[Location] = [Location]()
var ref = Firebase(url: "<MYFIREBASEURL>")
var dictionaryOfRecommendations:[NSDictionary] = [NSDictionary]()
var currentlyConstructingLocation:Location = Location()
func getLocationData() {
let titleRef = self.ref.childByAppendingPath("events")
titleRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
var tempDict = [NSDictionary]()
for item in snapshot.children {
let child = item as! FDataSnapshot
let dict = child.value as! NSDictionary
tempDict.append(dict)
}
self.dictionaryOfRecommendations = tempDict
})
// Parse data from Firebase
// Loop through each dictionary and assign values to location object
var index:Int
for index in 0...dictionaryOfRecommendations.count {
// Current Json dictionary
let jsonDictionary:NSDictionary = self.dictionaryOfRecommendations[index]
self.currentlyConstructingLocation.title = jsonDictionary["title"] as! String!
self.currentlyConstructingLocation.locationsLatitudeArray = jsonDictionary["latitude"] as! Double
self.currentlyConstructingLocation.locationsLongitudeArray = jsonDictionary["longitude"] as! Double
// Append to Locations Array and start new Location
self.locationsArray.append(currentlyConstructingLocation)
self.currentlyConstructingLocation = Location()
}
// Notify the MainViewController that the Locations are ready.
...
}
Here's the updated correct code for the question above based on Jay's helpful guidance:
// Model to download location data for events.
//Firebase reference
var ref = Firebase(url: "<MYFIREBASEURL")
var locationsArray:[Location] = [Location]()
var dictionaryOfRecommendations:[NSDictionary] = [NSDictionary]()
var currentlyConstructingLocation:Location = Location()
func getLocationData() {
let titleRef = self.ref.childByAppendingPath("events")
titleRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
var tempDict = [NSDictionary]()
for item in snapshot.children {
let child = item as! FDataSnapshot
let dict = child.value as! NSDictionary
tempDict.append(dict)
}
self.dictionaryOfRecommendations = tempDict
self.ParseFirebaseData()
})
}
func ParseFirebaseData() {
// Parse data from Firebase
// Loop through each dictionary and assign values to location object
var index:Int
for index in 0...dictionaryOfRecommendations.count - 1 {
// Current Json dictionary
let jsonDictionary:NSDictionary = self.dictionaryOfRecommendations[index]
self.currentlyConstructingLocation.title = jsonDictionary["title"] as! String!
self.currentlyConstructingLocation.locationsLatitudeArray = jsonDictionary["latitude"] as! Double
self.currentlyConstructingLocation.locationsLongitudeArray = jsonDictionary["longitude"] as! Double
// Append to Locations Array and start new Location
self.locationsArray.append(currentlyConstructingLocation)
self.currentlyConstructingLocation = Location()
}
}

How to store Array in NSUserDefault in Swift?

So I've been trying for a few hours for a way to store an array to NSUserDefault and print them to the cells but the data is not saving as an array, it basically only saves one value at a time.
var emailData = [String]()
var passwordData = [String]()
#IBAction func addPressed(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()
emailData.append(addEmail.text!)
passwordData.append(addPassword.text!)
var storedEmail = defaults.objectForKey("emailData") as? [String] ?? [String]()
var storedPasswords = defaults.objectForKey("passwordData") as? [String] ?? [String]()
// then update whats in the `NSUserDefault`
defaults.setObject(emailData, forKey: "emailData")
defaults.setObject(passwordData, forKey: "passwordData")
// call this after you update
defaults.synchronize() /*
NSUserDefaults.standardUserDefaults().setValue(addEmail.text, forKey: "email")
NSUserDefaults.standardUserDefaults().synchronize()
*/
}
So basically the data is not saving.
You can store Array too, by this way
let userDefault = NSUserDefaults.standardUserDefaults()
let arr = ["abc","xyz","pqr"]
userDefault.setObject(arr, forKey: "arr")
userDefault.synchronize()
let data = userDefault.objectForKey("arr") as! [String]
Save the Swift Array in Swift.
let kUserDefault = NSUserDefaults.standardUserDefaults()
kUserDefault.setObject(["KIRIT" , "MODI" , "FIRST" , "LAST"], forKey: "nameArray")
kUserDefault.synchronize()
Get Array
1. arrayForKey : You getting Swift Array
kUserDefault.arrayForKey("nameArray")!
2. objectForKey : You getting NSArray
kUserDefault.objectForKey("nameArray")!
3. valueForKey : You getting NSArray
kUserDefault.valueForKey("nameArray")
It is possible to store arrays in NSUserDefaults. But separating email and password in separate array is not suitable. You should store it as one object since they are related.
In your case an array of Dictionary objects is better, which is possible to store in NSUserDefaults as well, which you can retrieve as an array of Dictionary.
Here is the sample:
let userDefault = NSUserDefaults.standardUserDefaults()
var storedCredentials = userDefault.objectForKey("credentials") as? [[String:AnyObject]] ?? [[String:AnyObject]]()
let email =
[
"email" : addEmail.text!,
"password": addPassword.text!
]
storedCredentials.append(email)
userDefault.setObject(storedCredentials, forKey: "credentials")
userDefault.synchronize()
You can't save an array of [String] in NSUserDefault, if you look at the documentation :
For NSArray and NSDictionary objects, their contents must be property
list objects.
So what you can do is convert your [String] into NSData then save it into NSUserDefault.
// Store it as NSData
var emailData = [String]()
emailData.append("email1")
emailData.append("email2")
let emailIntoNSData = NSKeyedArchiver.archivedDataWithRootObject(emailData)
NSUserDefaults.standardUserDefaults().setObject(emailIntoNSData, forKey: "emailData")
// Retrieve it :
let emailFromNSData = NSUserDefaults.standardUserDefaults().objectForKey("emailData") as? NSData
if let emailFromNSData = emailFromNSData {
let emailArray = NSKeyedUnarchiver.unarchiveObjectWithData(emailFromNSData) as? [String]
if let emailArray = emailArray {
NSLog("Email Data : \(emailArray)") // ["email1","email2"]
// do something…
}
}

How to fetch elements of NSDictionary stored in an NSMutableArray in Swift?

I have stored my contacts as a dictionary on an mutable array by this method:
var addressBookReff: ABAddressBookRef = ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue()
var arrOfDictContacts:NSMutableArray = NSMutableArray()
let people:NSArray = ABAddressBookCopyArrayOfAllPeople(addressBookReff).takeRetainedValue()
for person in people{
if let name:String = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String {
let numbers:ABMultiValue = ABRecordCopyValue(person, kABPersonPhoneProperty).takeRetainedValue()
if let number:String = ABMultiValueCopyValueAtIndex(numbers,0)?.takeRetainedValue() as? String {
arrOfDictContacts.addObject(["\(name)":"\(number)"])
}
}
}
Here, arrOfDictContacts is my mutable array which contains name and number as dictionary. Like this :
arrOfDictContacts = ({ my = 12131;}, { doctor = 54445;}, { AL = 543212601;}, { customer = 121; } }
Now I have another array of names as
arrOfNames = [my, AL]
I want to get the respective numbers of the arrOfNames from arrOfDictContacts
ExpectedOutput :
arrOfNumbers = [12131, 543212601]
How can I do this?
Edit:
Since your array contains dictionaries, the way to do it is to check each of the dictionaries against your array. Like following:
var arrOfNumbers : [String] = []
for dict in arrOfDictContacts {
for name in arrOfNames {
if let value = dict[name] as? String {
arrOfNumbers.append(value)
}
}
}

Resources