Swift: Remove only the first object from the NSUserDefaults - swift

I create the Bus Ticket Booking App. so I have Dictionary with the Array in it. In which the recent Route search result is save into the NSUserDefaults. Now I want to print that result into the one TableView.
Now in that TableView I only want to show the last 10 That's all I can do perfectly but the problem is every time the result is save in to the UserDefaults so the size of the UserDefaults is increase so I just want to remove the Defaults So every time my array element remove Repeat While loop is call the number of the element in the UserDefaults (If I i have 30 element into it it run 20 times so like). This is what i'm doing for Dictionary.
var arrSearch = [[String:Any]]()
var searchBusVC:SearchBusViewController?
override func viewDidLoad() {
super.viewDidLoad()
if let arr = UserDefault["Search"] {
arrSearch.append(contentsOf: (arr as! [[String:Any]]))
repeat{
arrSearch.removeFirst()
}while (arrSearch.count > 10)
arrSearch.reverse()
}
self.tblSearch.reloadData()
}
So I want to remove the same from the UserDefaults Is it possible? This is my Table View Image.

If you are saving [[String: Any]] in UserDefaults means its like a normal way to remove objects from array. Once you done removing objects from array then save it to UserDefaults.
var recentRecords:[[String: Any]]? {
get {
return UserDefaults.standard.array(forKey:"recentRecord")
}
set {
var trimmed: [[String: Any]] = newValue
// Trim last 10 objects from array
if newValue.count >= 10 {
trimmed = newValue.suffix(10)
}
UserDefaults.standard.set(trimmed, forKey: "recentRecord")
}
}

Related

Swift Realm Results to Editable object or array

OK, I understand that I can not modify the results of a Realm Object.
So what is best way to change the data.
First I get all the Realm data as Results< Month >
let m = Month.getAllEntriesByDateAsc()
Now I need to loop through all the data to modify it. (This is a function to recalculate the entire table data.)
So I want to loop through the data and do something like:
for i in m {
var d = i
// perform calculations like
d.value = 9999
}
I want to do all the modifying on d.
Is these some sort of mapping I can use to create the new edible object from the Realm data?
Previously I did something like this:
for i in m {
let d = Month()
d.value = i.value
d.status = i.status
}
But there are now to many variables.
I guest what I need to so change the Realm Object to the Model object?
And the .toArray() stuff will not work inside the loop? Not sure why.
Thanks.
extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for i in 0 ..< count {
if let result = self[i] as? T {
array.append(result)
}
}
return array
}
}
From here

For loop appending for each cycle at start rather than just once through its iteration

I am trying to get the key/values appended to some arrays once each. So my result should be a singular occurrence of each key/value pair in my array. However, after each iteration the key/value pair is added and then the iteration restart back at the beginning again, adding the key/value pair again each time.
How can I make it only append each key/value pair once?
import UIKit
import PlaygroundSupport
var usernameScoreDict : [String:String] = ["erer":"eree", "veev":"veve", "tbtt":"bttbt", "umum":"muumu", "bvbv":"bbbcb"]
var unArray = [String]()
var hsArray = [String]()
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
usernameScoreDict.forEach { (key,value) in
print("key is - \(key) and value is - \(value)")
unArray.append(key)
hsArray.append(value)
}
}
}
You can use a for loop like this:-
for (key, val) in usernameScoreDict{
unArray.append(key)
hsArray.append(value)
}
Afterwards you can remove repeated value if any(as I don't think so it will happen) by using set:-
unArray = (Array(Set(unArray)))
hsArray = (Array(Set(hsArray)))
You can directly create arrays of keys and values from the dictionary
let keysArray = [String](usernameScoreDict.keys)
let valuessArray = [String](usernameScoreDict.values)

Why can't I get the index of a filtered realm List?

I'm trying to find the index of an item in a List<> object after the item has been appended to it, so that I can insert into a tableview.
The tableview is sectioned with .filters so I have to apply the filter before looking for the indexPath. However, the filter appears to break the indexOf functionality.
I noticed that the function .map has the same effect.
import UIKit
import RealmSwift
class Model: Object {
#objc dynamic var title: String = ""
let items = List<Model>()
}
class ViewController: UIViewController {
var models: Results<Model>?
var parentModel: Model?
var items = List<Model>()
let realm = try! Realm()
override func viewDidLoad() {
super.viewDidLoad()
if !UserDefaults.standard.bool(forKey: "IsNotFirstTime") {
populateRealm()
UserDefaults.standard.set(true, forKey: "IsNotFirstTime")
}
models = realm.objects(Model.self)
parentModel = models!.first
items = parentModel!.items
let child = Model()
child.title = "Child"
try! realm.write {
parentModel!.items.append(child)
}
print(items.index(of: child)) // prints correct value
print(items.filter({ $0.title == "Child" }).index(of: child)) // prints nil
}
func populateRealm() {
let parent = Model()
parent.title = "Parent"
try! realm.write {
realm.add(parent)
}
}
}
The first print finds the object, but the second print doesn't, despite the mapping having no overall effect.
The strange thing is that the object IS in the filtered list, doing:
print(items.filter({ $0.title == "Child" }).first
Returns the object, so it is there.
Edit
On further inspection, it looks like it's not the filter but the conversion of array type that breaks the functionality, converting to array without a filter does the same thing.
print(Array(items).index(of: child)) // prints nil
When you want to use mapping you should add an attributes to map your objects according to it for example
print(items.map({ $0.id }).index(of: child.id))
if you use it on this way it will return what you expected
I figured out the solution. The filter syntax I used .filter({ $0.title == "Child" }) isn't the Realm filter, and converts the List to a LazyFilterCollection<List<Model>>, which doesn't seem to be compatible with searching for the index of a realm object.
The fix was to use the format .filter("title == %#", "Child"), which returns a realm Results object.

Trouble using UILocalizedIndexedCollation to filter a table view with the inputed user's name.

I'm new to this forum! I am having a little bit of trouble sorting my Person's array with the use of UILocalizedIndexedCollation.
Code
I created the following class:
#objc class Person : NSObject {
#objc var firstName: String!
#objc var lastName: String!
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
With the help of this class, I created a bunch of instances to be displayed and sorted alphabetically on the table view by their last names.
For me to do so, I created the following function:
func partitionObjects(array:[AnyObject], collationStringSelector:Selector) -> ([AnyObject], [String]) {
var unsortedSections = [[AnyObject]]()
//1. Create a array to hold the data for each section
for _ in self.sectionTitles {
unsortedSections.append([]) //appending an empty array
}
//2. Put each objects into a section
for item in array {
let index:Int = self.section(for: item, collationStringSelector:collationStringSelector)
unsortedSections[index].append(item)
}
//3. sorting the array of each sections
var sectionTitles = [String]()
var sections = [AnyObject]()
sectionTitles.append("Frequently Requested")
for index in 0 ..< unsortedSections.count { if unsortedSections[index].count > 0 {
sectionTitles.append(self.sectionTitles[index])
sections.append(self.sortedArray(from: unsortedSections[index], collationStringSelector: collationStringSelector) as AnyObject)
}
}
return (sections, sectionTitles)
}
With this function, I am able to assign my array of Person and array of titles to the returning values of the function:
var sectionTitles = [Person]()
var personsWithSections = [[Person]]()
var contacts = [Person]()
#objc func setUpCollation(){
let (arrayPersons, arrayTitles) = collation.partitionObjects(array: self.persons, collationStringSelector: #selector(getter: Person.lastName))
self.personsWithSections = arrayPersons as! [[Person]]
self.sectionTitles = arrayTitles
}
With this, I am able able to set up my whole table view and it works great. I get every person sorted up by their last name to their corresponding alphabetical section.
The Issue, Specifically
The problem is that if the user has only inputed their first name and not their last name, that Person object gets appended to the last section of the array, where objects with last names that start with numbers or special characters go.
How can I append these object's with only first names to the corresponding alphabetical
section if the user doesn't input a last name? The same goes with
numbers.
As you can see, my collationsStringSelector takes Person.lastName, I was thinking maybe I could create a computed variable that would return the right person's property under some conditions? I am not sure how I would do so. It would be nice to have some guidance or help!
ps: NEW to the forum! if I'm doing something wrong let me know guys! thanks

Appending to dictionary of [character: [object]] returns 0 key/value pair

I'm trying to show a tableview similar to contacts with my list of users.
I declare a global variable of friends that will store the first character of a name and a list of users whose first name start with that
var friends = [Character: [User]]()
In my fetch method, I do this
for friend in newFriends {
let letter = friend.firstName?[(friend.firstName?.startIndex)!]
print(letter)
self.friends[letter!]?.append(friend)
}
After this, I should have my friends array with the first letter of the name and the users that fall in it; however, my friends dictionary is empty.
How do I fix this?
Edit: I'm following this tutorial and he doesnt exactly the same.. Swift: How to make alphabetically section headers in table view with a mutable data source
Rather than using Character as the key, use String. You need to be sure to init the [User] array for every new First Initial key you insert into groupedNames. I keep an array of groupedLetters to make it easier to get a section count
var groupedNames = [String: [User]]()
var groupedLetters = Array<String>()
func filterNames() {
groupedNames.removeAll()
groupedLetters.removeAll()
for friend in newFriends {
let index = friend.firstName.index(friend.firstName.startIndex, offsetBy: 0)
let firstLetter = String(friend.firstName[index]).uppercased()
if groupedNames[firstLetter] != nil {
//array already exists, just append
groupedNames[firstLetter]?.append(friend)
} else {
//no array for that letter key - init array and store the letter in the groupedLetters array
groupedNames[firstLetter] = [friend]
groupedLetters.append(firstLetter)
}
}
}
Creating a Dictionary structure with Characters as keys & values as Array of User will be more succinct.
The error occurs because you are declaring an empty dictionary, that means you have to add a key / empty array pair if there is no entry for that character.
Consider also to consolidate the question / exclamation marks
class User {
let firstName : String
init(firstName : String) {
self.firstName = firstName
}
}
var friends = [Character: [User]]()
let newFriends = [User(firstName:"foo"), User(firstName:"bar"), User(firstName:"baz")]
for friend in newFriends {
let letter = friend.firstName[friend.firstName.startIndex]
if friends[letter] == nil {
friends[letter] = [User]()
}
friends[letter]!.append(friend)
}