Covert realm list to realm result - swift

just wondering, how do I convert List to Result?
Cause I'm doing filtering of region and areas, and when user selected region then area should show only those area in the region. And when I'm asigning my areas to a variable defined as var areas: Results<Area>!, I got the compile error
Cannot assign value of type 'List' to type 'Results!'
my code is as below
if let regionString = self.selectedRegionString {
let region = self.realm.objects(Region).filter("name = '\(regionString)'").first
self.areas = region!.areas //this line is the problem
} else {
self.areas = self.realm.objects(Area)
}

I think you should define your self.areas like
var areas: List<Area>
It should have the same model class
Results is used for Realm's queries returned value.

Related

Query MongoDB Realm array only at first index

I need to query MongoDB Realm from synced iOS and Android app. In Swift I can write something like this:
let dictionary = realm?.objects(myReamlObject.self)
let results = dictionary?.where {
$0.senses.glosses.term == "the term I want"
}
or using predicate:
let results = dictionary?.filter("ANY senses.glosses.term == %#", "the term I want")
Both work well, but I don't want to check ALL senses.glosses.term.
Every entry has (or could have) many senses and many glosses.
I would like to check term of first senses in first glosses only.
Something I would write like this:
let results = dictionary?.where {
$0.senses[0].glosses[0].term == "the term I want"
}
But it gives error:
Referencing subscript 'subscript(_:)' on 'Query' requires that
'List<myRealmObject_senses>' conform to 'RealmKeyedCollection'
Any suggestion on how to query only first index of an array in MongoDB Realm? Thank you
Let me re-state the question
How to query a Realm objects' List property - but only query on the first
element in the List.
The answer is going to depend on the amount of results being worked with.
Here's how to do it in a way that's O.K. for small datasets but NOT RECOMMENDED
Your models were not included in the question so let me use a simplified model of a PersonClass that as a List of DogClass objects
class PersonClass: Object {
#Persisted var name = ""
#Persisted var dogList = List<DogClass>()
}
class DogClass: Object {
#Persisted var name = ""
}
The idea here is to use Swift high-level functions to only test the first item in each persons doglist for a match (this can be applied to other languages as well)
//get all the people
let peopleResults = realm.objects(PersonClass.self)
//use the high-level Swift function compactMap to return all of
// the people whose first dog is named "Spot"
let persons = peopleResults.compactMap { person -> PersonClass? in
if person.dogList.first?.name == "Spot" {
return person
}
return nil
}
The downside is that this code overrides a fundamental advantage of Realm - that Realm objects are lazily loaded if Realm functions are used e.g. as soon as a high-level Swift function is used, ALL of the objects are loaded into memory, potentially overwhelming the device.
A better option is to simply add a managed property to the PersonClass that also points to the 0'th element in the list.
class PersonClass: Object {
#Persisted var name = ""
#Persisted var dogList = List<DogClass>()
#Persisted var mainDog: DogClass?
func addMainDog(withDog: DogClass) {
self.dogList.append(withDog)
self.mainDog = withDog
}
}
as you can see, there's also a function to add that first dog to the list and also populates the mainDog property which points to the same object. It's one property so the overall impact is very low but the advantages for simple queries are very high.
From there the query becomes trivial
let peopleResults = realm.objects(PersonClass.self).where { $0.mainDog.name == "Spot" }
Expanding on this, you could save the 0th element of each List object in the Parent object or even have a property in each child object that points to the first element in it's respective list.

Delete specific object from LinkingObjects list - Realm Swift

I am currently trying out Realm on a test project and I have been struggling with removing a specific object from a List. LensDBObject and ListDBObject. LensDBObject contains a list of lenses and ListDBObject are lists of existing lenses. A lens can be in multiple lists and I'd like to remove a specific lens from a specific list but not remove if from the other lists.
Below are my two classes:
#objcMembers class LensDBObject: Object {
dynamic var id = UUID().uuidString
dynamic var manufacturer = ""
dynamic var series = ""
dynamic var serial = ""
dynamic var isSelected = false
override static func primaryKey() -> String? {
return "id"
}
let objects = LinkingObjects(fromType: ListDBObject.self, property: "lensList")
}
#objcMembers class ListDBObject: Object {
dynamic var listName = ""
let lensList = List<LensDBObject>()
}
Below is my code to find a specific lens in the list I want. The values returned are what I expect.
let listToSearch = realm.objects(ListDBObject.self).filter("listName == %#", "List 542")
print(listToSearch)
let filteredResults = listToSearch[0].lensList.filter("manufacturer == %# AND series == %# AND serial == %#", "Panavision" , "Primo Prime", "407")
print(filteredResults)
However, when I try to delete filteredResults, it deletes it from the lensDBOject altogether. I just want to be able to delete this specific lens from this specific list.
try! realm.write {
realm.delete(filteredResults)
}
I tried using for loops to get the index of the lens in the list and then delete it directly from that. But it still deletes the lens everywhere.
Am I missing something? Should I be using a one-to-many relationship as opposed to a LinkingObject?
Thanks for you help!
Try something like this. You only want to remove the lens from the list, not delete it from the Realm.
try! realm.write {
filteredResults.forEach { lens in
if let index = listToSearch[0].lensList.index(of: lens) {
listToSearch[0].lensList.remove(at: index)
}
}
}
Note that this will remove from that one specific list all lenses that match your filter.
Edit: Updated to reflect Realm's custom List class.
The if let is required, because index(of:) could potentially return nil if the object is not found in the list. Additionally, we must do it one item at a time rather than getting all the indexes first, since removing an item would cause the index array to be wrong.

contextual type cgfloat cannot be used with array literal

I'm using UIImage+Gradient.swift file to add gradient to my label, but I get this error:
contextual type cgfloat cannot be used with array literal
I've reviewed some FAQ Q&A but I'm still confused.
Here is the code:
let components = colors.reduce([]) { (currentResult: [CGFloat], currentColor: UIColor) -> [CGFloat] in
var result = currentResult
let numberOfComponents = currentColor.cgColor.numberOfComponents
let components = currentColor.cgColor.components
if numberOfComponents == 2 {
result.append([components?[0], components?[0], components?[0], components?[1]])
} else {
result.append([components?[0], components?[1], components?[2], components?[3]])
}
return result
}
Lines which are giving error are these:
result.append([components?[0], components?[0], components?[0], components?[1]])
result.append([components?[0], components?[1], components?[2], components?[3]])
This error has to do with trying to make a variable that is not an array be set to an array. For example this would produce a similar error:
var myFavSnacks:String = ["Apples","Grasses","Carrots"] //gives similar error
In your case, it thinks you want to add an array of CGFloats to one index in your array, rather than adding a number of CGFloats to your array.
To add multiple items to an array at once use contentsOf: like this:
colors.append(contentsOf: ["red", "blue"])
//adds strings "red" and "blue" to an existing array of strings called colors
From documentation available here:
https://developer.apple.com/reference/swift/array

How to address key of retrieved object, in Realm, Swift?

I have created DB for my iOS mobile app using Realm, writing with Swift.
I am trying to find way to look up for matching username and password in DB
This is what I have currently, Attempting filtering and get an object with matching username
I am trying to address attribute/key called password from retrieved object
#IBAction func SignInCheck(sender: AnyObject) {
let realm = try! Realm()
var currentlogin = realm.objects(UserRecords).filter("name = LogUsernameTextField.text")
//this line causes SIGABRT to be thrown
if currentlogin.password == LogPasswordTextField.text { //This is the incorrectly addressed line
....
}
}
The issue maybe that I am not understanding how objects work in the right way, nor knowing the right syntax to address what I want.
I suspect it is in form of Result but I am still unable to find way to address desired information.
Here is the table structure for your information
class UserRecords: Object {
dynamic var username: String = ""
dynamic var password: String = ""
dynamic var latitude: Float = 0
dynamic var longtitude: Float = 0
}
I am open for suggestions better solution and ways of looking up/matching passwords in the table too, if any.
Thanks in advance
You are using a property called name in your filter string but in your UserRecords class the property is called username. Also you have to create the filter string differently:
var currentlogin = realm.objects(UserRecords).filter("username = '\(LogUsernameTextField.text!)'")
Also be aware that the filter method returns a list of UserRecord objects that match the filter and not a single object. So calling if currentlogin.password == ... will cause an error.
The list only has 1 item (because the username is unique) but it is still a list. So to access the UserRecord object you can call first:
var currentlogin = realm.objects(UserRecords).filter("name = LogUsernameTextField.text!").first
Also the text property of UITextField returns an Optional, so you have to unwrap it.

Return specific result from Realm Query

I'm using Realm to persist data entries of Animals. Each animal entry has a type, weight, and color. I'm trying to say if an animal's type is equal to monkey, then return the monkey's weight.
class Animal: Object {
dynamic var type = ""
dynamic var weight = 0.0
dynamic var color = ""
}
let animalResults = Realm(path: Realm.defaultPath).objects(Animal)
I believe I need to filter & map the results, but I'm unsure how to do this with a Realm Object.
You can use filter method chaining to the results. If you would like to retrieve only monkey type animals, like following:
let monkeys = Realm().objects(Animal).filter("type == %#", "monkey")
If you want to collect the weight of monkeys, you can use map function to the results.
let weightOfMonkeys = map(monkeys) { $0.weight }