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)
}
}
Related
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
}
I have been trying to create model like firebase database structure. I can able to create normal string, bool and int value but not able to do array and dictionary.
Here is my firebase structure screenshot:
Here i am trying to add groupMembers and to in model like firebase structure.
Here is my Model i tried to create with array and dictionary:
import Foundation
import RealmSwift
class RealmMessages: Object {
#objc dynamic var messageText : String?
#objc dynamic var sender: String?
let chatCreatedDateTimee = List<timeStampValue>()
#objc dynamic var chatId: String?
#objc dynamic var from: String?
#objc dynamic var groupMemberss : [String: String]!
let groupMemebersCount = RealmOptional<Int>()
#objc dynamic var task: Bool = false
#objc dynamic var to: Array = [String]()
}
class timeStampValue: Object {
let timestamp = RealmOptional<Int>()
}
Here is my contoller code: Trying to add value into realm database.
var dic : [String : String] = [:]
var cont = ["one", "two", "three"]
var oneVal = ["909090": "SELF", "808080": "Other"]
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
print("realm location:::\(String(describing: Realm.Configuration.defaultConfiguration.fileURL))")
let myMessage = RealmMessages()
myMessage.messageText = "Diva"
myMessage.sender = "yIvq1mQxjfZpjs1ybRTTlDOmUKV2"
let timevalue = timeStampValue()
timevalue.timestamp.value = 123123131
myMessage.chatId = "+918000080000"
myMessage.from = "+918000080000"
myMessage.groupMemberss = oneVal
myMessage.to = cont
try! realm.write {
realm.add(myMessage)
}
}
How to get groupMemberss and to structure in realm database like firebase. And how to create array and dictionary in realm
There are a number of solutions but here's two.
Assuming the data has been read in and the data from the groupMembers snapshot is sitting in a dictionary var that looks like this
let groupMembersDict = [
"919": "participant",
"111": "observer",
"222": "participant"
]
To store that in Realm, you can work with primitives and store each key and value in a separate List (think: Array) or you can leverage a managed Realm object and store those in a List.
If you want to keep the data within an object; here's what it would look like.
class GroupData: Object {
#objc dynamic var num = ""
#objc dynamic var type = ""
convenience init(withNum: String, andType: String) {
self.init()
self.num = withNum
self.type = andType
}
}
Here's the main object showing both options; either option 1: store the key value pairs in two arrays, or option 2: use the above GroupData object to store the key value pairs together
class Messages: Object {
#objc dynamic var messageText = ""
//option 1: two lists of primative strings that can be accessed like an array.
// downside is managing two lists
let groupNum = List<String>()
let groupType = List<String>()
//option 2: a list of members using another Realm object
let groupNumType = List<GroupData>()
}
And some code to create two messages, one of each type
let msg0 = Messages()
msg0.messageText = "My message"
for member in groupMembersDict {
msg0.groupNum.append( member.key )
msg0.groupType.append( member.value )
}
let msg1 = Messages()
msg1.messageText = "This message"
for member in groupMembersDict {
let aGroup = GroupData(withNum: member.key, andType: member.value)
msg1.groupNumType.append(aGroup)
}
store them in realm
realm.add(msg0)
realm.add(msg1)
read them both in an display the message from option 2. Option 1 would be just iterating over the arrays to print the group data
let messageResults = realm.objects(Messages.self)
for msg in messageResults {
print(msg.messageText)
for group in msg.groupNumType {
print(group.num, group.type)
}
}
Keep in mind that all managed properties must be primitives: NSString, NSDate, NSData, NSNumber or List, Results, RLMLinkingObjects, or subclasses of RLMObject like the GroupData shown above.
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)
}
I have my class defined as:
class Device: Object {
dynamic public var assetTag = ""
dynamic var location = ""
}
I also have two arrays defined as:
let array = ["12", "42", "52", "876"]
let array2 = ["SC", "EDS", "DS", "EF"]
I would like to loop through the first array and add each value to my realm Device.assetTag object and loop through my second array and add each value to the Device.location object.
I tried using the code from the Realm readme to just add data from the first array but it did not seem to loop:
let realmArray = Device(value: array)
let realm = try! Realm()
try! realm.write {
realm.add(realmArray)
}
You have two arrays one that holds asetTags and Another location so first you have to build the object from those. You can do something like following (probably refactoring needed)
class Device: Object {
dynamic public var assetTag = ""
dynamic var location = ""
}
class Test {
let assetTags = ["12", "42", "52", "876"]
let locations = ["SC", "EDS", "DS", "EF"]
func saveDevice() {
let realm = try! Realm()
try! realm.write {
let allDevices = getDeviceArray()
for device in allDevices {
realm.add(device)
}
}
}
func getDeviceArray() -> [Device] {
let requiredDevices = [Device]()
var index = 0
for tag in assetTags {
let locationForTag = locations[index]
let device = Device()
device.assetTag = tag
device.location = locationForTag
requiredDevices.append(device)
index += 1
}
return requiredDevices
}
}
Remember to put loop within realm.write for batch operation, this ensure the connection to write is made once.
Let's assume I have:
class Dog: Object {
dynamic var race = ""
dynamic var name = ""
override static func primaryKey() -> String? {
return "race"
}
}
class Person: Object {
dynamic var name = ""
dynamic var address = ""
dynamic var dog: Dog?
override static func primaryKey() -> String? {
return "name"
}
}
First I create a Dog and save it:
let dog = Dog()
dog.race = "Dalmatian"
try! realm.write {
realm.add(dog, update: true)
}
Now I create a Person in a different class. The docs are quite a bit unclear about this scenario. Do I need to save changes for the Dog first before creating the relationship?:
let person = Person()
person.name = "Jim"
// retrieve dog from realm:
if let dog = realm.objectForPrimaryKey(Dog.self, key: "Dalmatian") {
dog.name = "Rex" // Owner gives dog a new name
// Question:
// Saving changes to Rex: is this step neccessary?
try! realm.write {
realm.add(dog, update: true)
}
person.dog = dog
}
try! realm.write {
realm.add(person, update: true)
}
No, and it will cause a crash
if let dog = realm.objectForPrimaryKey(Dog.self, key: "Dalmatian") {
dog.name = "Rex" // Owner gives dog a new name
person.dog = dog
}
if you want update the dog's name, write like this:
if let dog = realm.objectForPrimaryKey(Dog.self, key: "Dalmatian") {
try! realm.write({
dog.name = "Rex"
})
person.dog = dog
}
see more: Realm.io/updating-objects
You can setup a whole object graph as unmanaged objects and persist them all by one call. So you don't need to persist the Dog first and retrieve it again to be able to use it in a relationship.
let dog = Dog()
dog.race = "Dalmatian"
let person = Person()
person.name = "Jim"
person.dog = dog
try! realm.write {
realm.add(person, update: true)
}