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

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.

Related

Convert filter expression to NSPredicate format

I would like to perform this filter method using NSPredicate, but I'm having trouble converting the syntax.
objectsCollection.filter { $0.stringIds.contains(id) }
Sample class
class Object {
let stringIds: [String]
}
let objectsCollection: [Object]
let id = "The id we want to look for"
objectsCollection.filter { $0.stringIds.contains(id) }
My attempt with NSPredicate
This is how I thought it would work, but seems like it doesn't.
let filter = NSPredicate(format: "%# IN stringIds", id)
objectsCollection.filter(filter)
Error
reason: 'Expected object of type (null) for property 'stringIds' on object of type 'Object', but received: 6011ea4dda6853a3af97376e'
There are a few issues that need to be addressed.
This
let stringIds: [String]
is not a realm object and will not be persisted in Realm.
That needs to be a List property and the object type of the list is another Realm object. Realm Lists do not support primitives (very well). Also, don't name your objects the same name as another object.
class MyClass: Object {
let myStringIdList = List<MyStringIdClass>
}
and
class MyStringIdClass: Object {
#objc dynamic var myId = ""
}
to then get all of the MyClass objects that had a certain stringId in their list
let results = realm.objects(MyClass.self).filter("ANY myStringIdList.myId == %#", idToFind)
The string inside .filter can also be an NSPredicate if needed.
You can also use LinkingObjects to navigate back to the MyClass objects as well.
One other thing, when you cast realm objects to an array, they loose their connection to realm and are no longer live updating objects.
Also, Realm objects are lazily loaded meaning that thousands of objects have very little memory impact. Casting them to an array however, loads ALL of that data and can overwhelm the device with a large data set.

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

RealmSwift. Difficulties initializing List after converting to Swift 4

I've got a task to convert an existing project to Swift4 (from Swift 2.3, don't ask O_o). Managed to fix almost everything except this issue using RealmSwift:
Old code:
class func myFunc() -> List<MyClass> {
let realm = try! Realm()
return List(realm.objects(MyClass).sorted("name", ascending: true))
}
Getting compiler error for the return statement:
Argument passed to call that takes no arguments
When I trying to fix like this, compiler is silent, but the function doesn't do its job:
return List<MyClass>()
So which is then the right way to initialize List with a collection of custom objects? Please, help!
List doesn't have an initializer accepting a Results instance in RealmSwift 3.1.0 (I'm not sure since when though). List's only initializer doesn't take any input arguments and it creates an empty List instance.
You can work around this by creating an empty List using the only initializer, then calling append to add the elements of the Results collection to the list.
func myFunc() -> List<MyClass> {
let realm = try! Realm()
let list = List<MyClass>()
list.append(objectsIn: realm.objects(MyClass.self).sorted(byKeyPath: "name", ascending: true))
return list
}

Modifying Realm values swift using map

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