Modifying Realm values swift using map - swift

I want to modify model data in Realm database in Swift App. Here is my code:
try! realm.write {
realm.objects(CompanyModel.self).map({ (model) in
model.isSelected = true
})
}
Idea is simple, iterate through models and change isSelected bool property to true. But look like it not work. Why?

You shouldn't use map if you want to modify the original Results instance and hence the model objects stored in your Realm. 'map' is not a mutating function, it iterates through your array (or in this case, Results), applies a transformation to each element of the sequence, then returns a new sequence containing the results of the transformation.
What you would actually need is the forEach function, which only iterates through the elements of an Array and executes the closure for each element,but doesn't return a new Array. I am currently not able to test it, but I since forEach is a member function of Array and not of NSFastEnumeration, from which Results inherits, I think you cannot use forEach on a Results instance, so you need to use a regular for loop to do this.
try! realm.write {
for model in realm.objects(CompanyModel.self) {
model.isSelected = true
}
}

Related

Convert Realm list of Strings to Array of Strings in Swift

I'm just starting up with RealmSwift, and I'm trying to store an array of Strings in Realm. It doesn't work, so now I'm using List<String>() as an alternative. However, how do I convert these Realm Lists back to [String] again? And if I can't do that, are there any alternatives?
Thanks
However, how do I convert these Realm Lists back to [String] again
You can simply cast List to Array, because List has Sequence Support:
let list = List<String>()
let array = Array(list)
Bear in mind that by converting to an array you'll lose the 'dynamic' quality of a Realm collection (i.e. you'll receive a static array, whereas keeping the original List will provide automatic updating should the source change). But you can create an array by using an extension, e.g.:-
extension RealmCollection
{
func toArray<T>() ->[T]
{
return self.compactMap{$0 as? T}
}
}
Then use:-
let stringList = object.strings.toArray()
Where object is the realm object, and strings is your field.
Here are the details. how to assign an array in the realm list model.
jim.dogs.append(objectsIn: someDogs)

Realm Swift - Convert an array of results into an array of Ints

I want to convert the results from my Realm data into Int.
Here is an example of how I want to use this.
let results = realm.objects(Data.self)
print(results)
However the result is type Results<Data> and cannot be converted into a Int but the results is an Int.
Just to be clear I want an array of Int from my results
You can simply use Array(realm.objects(RealmType.self)), which will convert the Results<RealmType> instance into an Array<RealmType>.
However, there are other serious flaws with your code. First of all, neither of the last two lines will compile, since firstly realm.objects() accepts a generic input argument of type Object.Type and Data doesn't inherit from Object. You can't directly store Data objects in Realm, you can only store Data as a property of a Realm Object subclass.
Secondly, myArray[results] is simply wrong, since results is supposed to be of type Results<RealmType>, which is a collection, so using it to index an Array cannot work (especially whose Element type is different).
It appears that based on the number of results from the database, you want to select an object from the array.
You can get the number of items in an array with .count. Be certain that an object exists at the specified index in the array, or your application will crash!
let numberOfResults = results.count
if myArray.count > numberOfResults {
let object = myArray[numberOfResults]
print(object)
}

Trying to understand map function for collection of structs

Please can someone explain the following code like I'm 5. I know what it's doing, changing all isLocked Bools to true in a struct array of type Person. I'm just having trouble with "storytelling" the syntax to myself.
people = people.map({
(p) -> Person in
var mod = p
mod.isLocked = true
return mod
})
Thanks.
map lets you make a new array from an existing one by applying some transform closure to all of its elements. Unfortunately, in this example, your closure is returning the same elements that it takes, so if your Person is a class (rather than a struct), the map is completely unnecessary, and the code above will simply do the same thing as:
people.forEach { $0.isLocked = true }
If Person were a struct instead of a class, OTOH, then the map would have meaning, because you'd need to make a copy of each of the objects in order to modify it.
In the case of a struct, the map creates a new array consisting of copies of each Person struct in the array, with each copying having its isLocked property set to true:
people = people.map {
(p) -> Person in
var mod = p // make a copy of each Person, store it in 'mod'
mod.isLocked = true // change the isLocked property of the copy to true
return mod // return the modified copy
}

LazyFilterBidirectionalCollection<Results<datatype>>' to expected argument type '[datatype]'

After I convert my project from swift 2.3 to swift 3 , I got this error in Realm Filter I can't get filter result in array :
func filterUsers(_ searchText: String, completion: (([Lawyer]) -> Void)) {
let bgRealm = try! Realm() // Filter the whole list of users
let results = bgRealm.objects(Lawyer.self).filter { (cc) -> Bool in
cc.name.contains2(searchText) ||
cc.name.contains2(searchText) ||
cc.phoneNumber2.contains2(searchText)
}
print(results)
completion(results)
}
filter, map, etc. are lazy operations on the Results returned by objects. This is implemented in types such as LazyFilterBidirectionalCollection<T>. To actually perform the filtering and get an array of results, you need to promote this collection to an array by wrapping in an Array initializer (e.g. Array(bgRealm.objects...))
From the docs:
Queries return a Results instance, which contains a collection of
Objects. Results have an interface very similar to Array and objects
contained in a Results can be accessed using indexed subscripting.
Unlike Arrays, Results only hold Objects of a single subclass type.
All queries (including queries and property access) are lazy in Realm.
Data is only read when the properties are accessed.

Implementing a multimap in Swift with Arrays and Dictionaries

I'm trying to implement a basic multimap in Swift. Here's a relevant (non-functioning) snippet:
class Multimap<K: Hashable, V> {
var _dict = Dictionary<K, V[]>()
func put(key: K, value: V) {
if let existingValues = self._dict[key] {
existingValues += value
} else {
self._dict[key] = [value]
}
}
}
However, I'm getting an error on the existingValues += value line:
Could not find an overload for '+=' that accepts the supplied arguments
This seems to imply that the value type T[] is defined as an immutable array, but I can't find any way to explicitly declare it as mutable. Is this possible in Swift?
The problem is that you are defining existingValues as a constant with let. However, I would suggest changing the method to be:
func put(key: K, value: V) {
var values = [value]
if let existingValues = self._dict[key] {
values.extend(existingValues)
}
self._dict[key] = values
}
}
I feel that the intent of this is clearer as it doesn't require modifying the local array and reassigning later.
if var existingValues = self._dict[key] { //var, not let
existingValues += value;
// should set again.
self._dict[key] = existingValues
} else {
self._dict[key] = [value]
}
Assignment and Copy Behavior for Arrays
The assignment and copy behavior for Swift’s Array type is more complex than for its Dictionary type. Array provides C-like performance when you work with an array’s contents and copies an array’s contents only when copying is necessary.
If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other.
For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array. If and when array copying does take place, the copy behavior for an array’s contents is the same as for a dictionary’s keys and values, as described in Assignment and Copy Behavior for Dictionaries.
See: https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11
Buckets is a data structures library for swift. It provides a multimap and allows subscript notation.
One easy way to implement a multi-map is to use a list of pairs (key, value) sorted by key, using binary search to find ranges of entries. This works best when you need to get a bunch of data, all at once. It doesn't work so well when you are constantly deleting and inserting elements.
See std::lower_bound from C++ for a binary search implementation which can be easily written in swift.