Why write function not working in realm on swift? - ios

Working with realm 5.3.0 on swift 5.2. I have 2 cases: when I want to add new item to table and when I want to update. Function realm.add(_:update:) have to solve my problem, but item is creating and cannot updating. When I try to update, I got:
Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.
There are method, where I calling write function:
try! realm.write {
realm.add(note, update: .modified)
}
And model:
class Note: Object {
#objc dynamic var id : String = ""
#objc dynamic var name : String = ""
#objc dynamic var descr : String = ""
#objc dynamic var dateTime : Date = Date()
override static func primaryKey() -> String? {
return "id"
}
init(id: String, name: String, descr: String, dateTime: Date) {
self.id = id
self.name = name
self.descr = descr
self.dateTime = dateTime
}
required init() {}
}

You just need to update your object inside write scope instead of using realm.add command again. Realm will automatically update the object in database
try! realm.write {
//Modify Node here
}

Related

Retrieve a single Realm object using Primary key - Error : Invalid Object ID string must be 24 hex digits

I am trying to get a single object using primary key but it never works and cannot figure out what I missed
My Realm data model is as follows
class Chapter : Object {
#objc dynamic var title = ""
#objc dynamic var chapterID = 0
#objc dynamic var bookmark = 0.0
#objc dynamic var marked = false
let notes = List<Notes>()
override class func primaryKey() -> String? {
return "chapterID"
}
}
func addNote(note: Note, chapterID: Int ) {
objectWillChange.send()
do {
let chapter = try Realm().object(ofType: Chapter.self, forPrimaryKey: "\(chapterID)")
// code to append note
}
catch let error {
// Handle error
print("Error in retrieving chapter no. \(chapterID)")
print(error.localizedDescription)
}
When I try to retrieve object by chapterID as primary key using Realm().object(ofType: forPrimaryKey:) or instance of Realm realm.object(ofType:forPrimaryKey:
I got the following error. e.g. for id 2
Invalid Object ID string '2': must be 24 hex digits
Thanks for any tips
chapterID is an Int so you shouldn't be passing a String when you try to fetch the Chapter. Just pass in an integer value.
let chapter = try Realm().object(ofType: Chapter.self, forPrimaryKey: chapterID)
Depending on which Realm you are using, I would recommend the newer syntax:
class Chapter: Object {
#Persisted var title = ""
#Persisted(primaryKey: true) var chapterID = 0
#Persisted var bookmark = 0.0
#Persisted var marked = false
}

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

Adding new Object to existing List in Realm

I have two classes. First looks like that:
class Person: Object {
dynamic var owner: String?
var dogs: List<Dogs>()
}
and second class which looks like that:
class Dogs: Object {
dynamic var name: String?
dynamic var age: String?
}
and now in ViewController in 'viewDidLoad' I create object Person with empty List and save it in Realm
func viewDidLoad(){
let person = Person()
person.name = "Tomas"
try! realm.write {
realm.add(Person.self)
}
}
it works great and I can create Person, problem begins when I try to read this data in SecondViewController in ViewDidLoad doing it:
var persons: Results<Person>?
func viewDidLoad(){
persons = try! realm.allObjects()
}
and try to add new Dog to List doing it in button action:
#IBAction func addDog(){
let newDog = Dogs()
newDog.name = "Rex"
newDog.age = "2"
persons[0].dogs.append(newDog)
// in this place my application crashed
}
Here my app is crashing with an information: Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first. How can I add new Dog to List and how can I update person[0]?
I use SWIFT 3.0
The persons property is of type Results<Person>, which is a collection containing Person objects that are managed by a Realm. In order to modify a property of a managed object, such as appending a new element to a list property, you need to be within a write transaction.
try! realm.write {
persons[0].dogs.append(newDog)
}
Write something like this:
if let person = persons?[0] {
person.dogs.append(newDog)
}
try! realm.write {
realm.add(person, update: true)
}
Please check how are you getting realm. Each time you call defaultRealm, you are getting new realm.
Side Note: Besides adding the code inside the write transaction which solves your issue, you could query Person by name as follow...
#IBAction func addDog(){
let newDog = Dogs()
newDog.name = "Rex"
newDog.age = "2"
let personName = realm.objects(Person.self).filter("name = 'Tomas'").first!
try! realm.write {
personName.dogs.append(newDog)
}
}
Add object for Realm Database
class Task : Object {
#objc dynamic var id : Int = 0
#objc dynamic var name = ""
#objc dynamic var phone = ""
#objc dynamic var address = ""
}
#IBAction func buttonSave(_ sender: Any) {
let realm = try! Realm()
let user = Task()
user.id = 0
user.name = (txtName.text! as NSString) as String
user.phone = (txtPhone.text! as NSString) as String
user.address = (txtAddress.text! as NSString) as String
try! realm.write {
realm.add(user)
print("user:",user.name)
}
}

Resources