Realm model contains property but not found it at runtime - ios

I am getting error as below
Invalid property name , reason: 'Property 'IsRecordDeleted' not found in object of type 'MyCustomModel'
Where as my Model is as Under
#objcMembers public class MyCustomModel : Object {
dynamic var Id : String = ""
dynamic var ProductId : String? = ""
dynamic var IsRecordDeleted : Bool? = false
dynamic var ProductBarcode : String? = ""
override public class func primaryKey() -> String? {
return "Id"
}
}
and I am making query like this :
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self).filter("IsRecordDeleted = false")
What could be problem here. I do not know why my app is crashing with the same error. But If I change the value like
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self).filter("ProductId = 0")
The app gets run, but crashed on when I use IsRecordDeleted in predicate.
Please tell me what could be problem

You can try
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self)
let filtered = mSavedItems.filter { $0.IsRecordDeleted == false }
and
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self)
let filtered = mSavedItems.filter { $0.ProductId == "0" }
For both
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self)
let filtered = mSavedItems.filter {
$0.IsRecordDeleted == false
&& $0.ProductId == "0"
}
//
let resultPredicate = NSPredicate(format: "ProductId == '0' AND IsRecordDeleted == false")
let filtered = mSavedItems.filter(resultPredicate)

I think you'll find that simply switching to filter blocks instead of string predicates might stop the crash, but will not produce the expected results.
This is because IsRecordDeleted never gets saved to the database. It is not a type that can be represented in Objective-C, therefore it cannot be dynamic, so Realm ignores it.
Take as an example the following class:
#objcMembers class MyObject: Object {
dynamic var id = ""
dynamic var testBool: Bool? = false
override static func primaryKey() -> String {
return "id"
}
}
And say we initialize them like this:
let obj1 = MyObject()
obj1.id = "1"
obj1.testBool = true
let obj2 = MyObject()
obj2.id = "2"
obj2.testBool = false
let realm = try? Realm()
try? realm?.write {
realm?.add(obj1, update: true)
realm?.add(obj2, update: true)
}
If we query Realm for these objects using realm.objects(MyObject.self), you'll get something like this
Results<MyObject> <0x7fe410c0ad90> (
[0] MyObject {
id = 1;
},
[1] MyObject {
id = 2;
}
)
And you'll see that in the database, there indeed is no property named testBool, which was our optional Bool.
You can easily see that the optional Bool may cause problems if you write it out like this instead:
class MyObject: Object {
#objc dynamic var id = ""
#objc dynamic var testBool: Bool? = false // This line will not compile.
override static func primaryKey() -> String {
return "id"
}
}
I'm curious why the IsRecordDeleted needs to be optional in the first place, since it seems to have a value from the get-go. If it doesn't, then something like this will work as expected:
#objcMembers public class MyCustomModel: Object {
dynamic var Id: String = ""
dynamic var ProductId: String? = ""
dynamic var IsRecordDeleted: Bool = false
dynamic var ProductBarcode: String? = ""
override public class func primaryKey() -> String? {
return "Id"
}
}
and you can query via string like you were trying to do in the first place.
If it has to be optional, then Realm provides a RealmOptional for this exact case, that you can look into here.

Related

Why does the Realm Set object work at random?

The function to use a set of Realm objects is always random.
Primary keys must not be changed and they must be unique.
So I added another variable for compare.
And I override isEqual(:) function.
See below my code.
class Model: Object {
#objc dynamic var key = ""
#objc dynamic var id = ""
override static func primaryKey() -> String? {
return "key"
}
override func isEqual(_ object: Any?) -> Bool {
if let object = object as? Model {
return id == object.id
} else {
return false
}
}
}
let model1 = Model()
model1.key = UUID().uuidString
model1.id = "hi"
let model2 = Model()
model2.key = UUID().uuidString
model2.id = "hi"
let model1Array = [model1]
let model2Array = [model2]
let set1 = Set(model1Array)
let set2 = Set(model2Array)
let result = set1.intersection(set2)
print(result) // []
let result = set1.intersection(set2)
print(result) // [Model { key = 9E814B97-D0CC-4550-BF7B-19645C1DB746; id = hi; }]
let result = set1.intersection(set2)
print(result) // []
let result = set1.intersection(set2)
print(result) // []
let result = set1.intersection(set2)
print(result) // [Model { key = 8A399388-1FA2-4699-8258-5DA5DFCEC203; id = hi; }]
Every time I run, the values come out randomly.
What did I do wrong?
For Set to work correctly, your objects need to have a correct implementation of Hashable. The Realm Object already implements Hashable, and presumably, the == implementation calls isEqual.
However, the hash should be consistent with isEqual as well, but you haven't overridden hash yet. You should implement hash such that two equal objects (as determined by isEqual) have equal hashes.
One way is to do it like this:
override var hash: Int {
return id.hash
}

How to store Array of Dictionaries to Realm Database in Swift

I am getting JSON data from server by api call in swift application.
So, I want to store that into Realm data base and again need to fetch to show in tableview.
I have no idea about Realm database, After, checked few forums, I got basic idea for creating Object class.
So, I have installed Realm pod file and imported that library to my classes.
My JSON data is
[{
"type": "story",
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Trending”,
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Technology”,
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Top”,
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
}
]
And I have each type keyword has different model class saved data from api data to show in Tableview
like
let storyObj = StoryModule()
let trending = StoryModule()
let technology = StoryModule()
let stotopryObj1 = StoryModule()
and I am saving each key value for every type
if abc.type == "story" {
let storyObj = abc.story
storyObj.authorname = storyObj?.authorname
storyObj.heroimage = storyObj?.heroimage
storyObj.headline = storyObj?.headline
storyObj.summary = storyObj?.summary
self.treningStoriesList.append(storyObj)
}
It is same for remaining Trending, Top and Technology objects.
and the Realm module is
import RealmSwift
class DemoInfo: Object {
#objc dynamic var category = ""
let items = List<DemoList>()
}
class DemoList : Object {
#objc dynamic var authorName = ""
#objc dynamic var imageUrl = ""
#objc dynamic var summary = ""
#objc dynamic var headLine = ""
}
And In MainViewController class,
let realmDB = try! Realm()
But, Here I got struck, How to save those storyObj,technology,top, etc module data and fetch.
Can anyone suggest me?
If you want to add a realm object in your db, you must define a primary key for each realm object classes. So, you need to change your JSON file, after you can create your realm objects like this;
DemoObject.swift
import RealmSwift
class DemoObject: Object {
#objc dynamic var id: String = ""
#objc dynamic var type: String = ""
#objc dynamic var subObject: SubObject?
override static func primaryKey() -> String? {
return "id"
}
}
SubObject.swift
import RealmSwift
class SubObject: Object {
#objc dynamic var id: String = ""
#objc dynamic var authorName: String = ""
#objc dynamic var imageUrl: String = ""
#objc dynamic var summary: String = ""
#objc dynamic var headLine: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
Then, you can use these codes to add your db.
let realm = try! Realm()
let demo = DemoObject()
demo.id = "1"
let sub = SubObject()
sub.id = "1"
sub.authorName = "Author Name"
sub.headLine = "Head Line"
sub.summary = "image Url"
demo.subObject = sub
try! realm.write {
realm.add(demo, update: true)
}

Cannot store lists - Realm Swift

I am trying to create a one to many relationship between medication table and side effects table. RealmObject is a custom class created from Object class.
Model definitions:
class Medication: RealmObject {
#objc dynamic var name : String?
#objc dynamic var form : String?
#objc dynamic var id : String?
let medToSideEffect = List<SideEffect>()
override class func primaryKey() -> String? {
return "id"
}
}
class SideEffect: RealmObject {
#objc dynamic var masterSideEffectId : String = ""
#objc dynamic var entityType : String = ""
#objc dynamic var entityId : String = ""
#objc dynamic var sideEffect : String = ""
#objc dynamic var id : String = ""
#objc dynamic var uniqueId : String = ""
override class func primaryKey() -> String? {
return "uniqueId"
}
}
Test code:
let medicationItem = Medication(dict: medication)
let sideEffectItems = List<SideEffect>()
for sideEffect in sideEffectList {
let sideEffectItem = SideEffect()
sideEffectItem.id = self.getMongoId()
sideEffectItem.entityType = "Medicine"
sideEffectItem.entityId = medicationItem.id!
sideEffectItem.sideEffect = (sideEffect as? String)!
sideEffectItem.uniqueId = "\(medicationItem.id!)_\(((sideEffect as? NSString)?.replacingOccurrences(of: " ", with: "_"))!)"
sideEffectItems.append(sideEffectItem)
medicationItem.medToSideEffect.append(sideEffectItem)
}
After this process, when i print the medicationItem, Output is this
Medication {
name = Paracetomol 650mg;
form = tab;
id = 5af96e79efb27f6bd5c25a66;
}
The side effects were supposed to be added to the medication object. but that is not the case anymore. It was working fine until the latest update Realm 3.11.0.
Please let me know, if the code is incorrect.
Maybe because yYou declare your list as 'immutable', and maybe because your list is a struct and therefore a copy is returned.
let medToSideEffect = List<SideEffect>()
And so it cannot be changed. Try (warning untested code)
public private(set) var medToSideEffect = List<SideEffect>()
and add a func
public func append(sideEffect: SideEffect) {
self.medToSideEffect.append(sideEffect)
}
The 'public private (set)' bit means that the list is visible externally but can only be modified by the owning class instance.
EDIT:
https://stackoverflow.com/a/52704564/6700116
Found the solution.
Go to your target Build Settings and set Reflection Metadata Level flag to All
The issue is discussed here.
https://github.com/realm/realm-cocoa/issues/5944#issuecomment-426948127

Realm Typecast issue Swift

I have to declare realm string property for to save the value get from API, but the issue is, I don't know which type of data will come from the server.
Sometimes I am getting String value and sometime Int.
Now how I will save data to the realm.
class Fields: Object {
#objc dynamic var default_value: String? = nil
}
API Response
{
access = 1;
default_value = " ";
},
{
access = 1;
default_value = 20;
}
This is the safest (where stringOrInt is the value you're receiving from the API):
fieldsObject.default_value = stringOrInt as? String
But you can also use string interpolation and inject the value directly into a string literal:
fieldsObject.default_value = "\(stringOrInt)"
You can try this solution
1- Relam object class
class Fields: Object {
#objc dynamic private var default_value: String? = nil
#objc var defaultValue: Any?{
didSet{
self.default_value = "\(defaultValue!)"
}
}
open override class func ignoredProperties()->[String] {
return ["defaultValue"]
}
}
1- Test add object in you'r DB
let obj = Fields()
obj.defaultValue = "ahmad"
let obj2 = Fields()
obj2.defaultValue = 1
let realm = try! Realm()
try! realm.write {
realm.add([obj,obj2])
}
3- Result

Is it possible to use dynamic variable for a class member variable

I have a class like
class Person {
var address:String
var number:String
var houseNo:String
var licenceNo:String
....
}
let jone = Person()
jone.number = "123456"
So in this i need to initialize the variable of person class one by one. And i have approx 30 variables in person class.
Is not there s simple way to do this ?
like I have all the keys coming from backend like "number = 123456". Is not there a way that i run a for loop and use something like.
for key in keys {
john."\(key)" = dict[key]
}
Is not there a way to shorten this lengthy procedure ?
You can try out this code
extension NSObject{
// fetch all class varible
func property() -> Mirror.Children {
return Mirror(reflecting: self).children
}
func propertyList() {
for (name, value) in property() {
guard let name = name else { continue }
print("\(name): \(type(of: value)) = '\(value)'")
}
}
}
Your class, set value like below code it's helpfull
class Person: NSObject {
var address:String = ""
var number:String = ""
var houseNo:String = ""
var licenceNo:String = ""
init(with response: [String: AnyObject]) {
for child in self.property() {
if let key = child.label, let value = response[key] {
self.setValue(value, forKey: key)
}
}
}
}
person.propertyList()
// Display all class property list
address: String = ''
number: String = ''
houseNo: String = ''
licenceNo: String = ''
Why don't use a Person method for load the backend response into a new Person object?
Somethind like that:
let jone = Person()
jone.loadDataFrom(response)
Or use a Person static method
let jone = Person.loadDataFrom(response)
static func loadDataFrom(response:Object) -> Person {
let p = Person()
...
set response data
...
return p
}

Resources