Add initial objects to Realm - ios

Let's say I have Queue class that has a unique title and can hold a list of objects from my other class Item.
class Queue: Object {
#objc dynamic var title = ""
let items = List<Item>()
override static func primaryKey() -> String? {
return "title"
}
}
I want to have n (probably 3-5) instances of Queue from the time the app gets installed available in the database, so I can access them at any time to add some Items to the list of items. Is there a way to create those queues and save them to the database just once when the app gets first launched and where exactly in the code should I do it?

You can check somewhere at the start of your app how many Queues you have right now:
let realm = try! Realm()
if realm.objects(Queue.self).isEmpty {
// no items, so you should create n items
}

Add new object for Realm
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

In realm When ever i am updating it is updating only in 0th index how to solve it?

in realm i given id = 0 and it is as primary key and it will be auto increment, but problem is while updating it is saving in the index path 0 as declare as id : Int = 0.
Where ever i update also it is only updating in 0th index only.
i want to update as per selected object.
What to do?
Program :-
class Discount: Object {
#objc dynamic var id : Int = 0
#objc dynamic var offerName : String = ""
#objc dynamic var percentage: Float = 0.00
#objc dynamic var segmentIndex : Int = 0
#objc dynamic var dateWise: Date?
override class func primaryKey() -> String? {
return "id"
}
//Incrementa ID
func IncrementaID() -> Int{
let realm = try! Realm()
if let retNext = realm.objects(Discount.self).sorted(byKeyPath: "id").last?.id {
return retNext + 1
}else{
return 1
}
}
}
Generally speaking, auto-incrementing primary keys are challenging to deal with and can cause headaches long term.
What's generally most important is ensuring primary keys are unique and using UUID strings is ideally suited for that.
class Discount: Object {
#objc dynamic var discount_id = UUID().uuidString
override static func primaryKey() -> String? {
return "discount_id"
}
}
There may be concern about ordering and often times that managed by either adding a class var to determine ordering; like a timestamp for example or if you want to preserve ordering, objects can be added to a List, which keeps the order, like an array.
To answer your specific question, the code in your question is not complete (it was partially pulled from another question). The reason is that for each object that's created, it must be written to realm first, then the next object's primary key is based on the prior object.
Here's an example.
#objcMembers class User: Object {
dynamic var uid: Int = 0
dynamic var username: String?
func getNextUid() -> Int {
let realm = try! Realm()
if let lastObject = realm.objects(User.self).sorted(byKeyPath: "uid").first {
let lastUid = lastObject.uid
let nextUid = lastUid + 1
return nextUid
}
return 1
}
override static func primaryKey() -> String? {
return "uid"
}
}
now the sequence to use this is as follows
let u0 = User()
u0.uid = u0.getNextUid()
u0.username = "User 0"
let realm = try! Realm()
try! realm.write {
realm.add(u0)
}
let u1 = User()
u1.uid = u1.getNextUid()
u1.username = "User 1"
try! realm.write {
realm.add(u1)
}
as you can see, each object needs to be written to realm in order to the next object to be queried to get the prior objects primary key.
It's a whole lot of potentially unnecessary work and code.
My advice: Stick with the UUID().uuidString for primary keys.

How to avoid adding the same data model that has the same primary key in realm database?

I have one to many relationship between two models, Product and WishList like the code below
class Product : Object {
#objc dynamic var productID : String = ""
#objc dynamic var name : String = ""
#objc dynamic var unitPrice: Double = 0.0
#objc dynamic var imagePath : String = ""
#objc dynamic var quantity = 0
#objc dynamic var hasBeenAddedToWishList : Bool = false
var parentCategory = LinkingObjects(fromType: WishList.self, property: "products")
convenience init(productID : String, name: String, unitPrice: Double, imagePath: String, quantity: Int = 1, hasBeenAddedToWishList: Bool = false) {
self.init()
self.productID = productID
self.name = name
self.unitPrice = unitPrice
self.imagePath = imagePath
self.quantity = quantity
self.hasBeenAddedToWishList = hasBeenAddedToWishList
}
override static func primaryKey() -> String? {
return "productID"
}
}
and WishList:
class WishList : Object {
#objc dynamic var userID: String = ""
var products = List<Product>()
}
I try to add or remove product to WishList using the code below when love button in the image above is pressed :
// 1. get the wishlist based on UserID
let allWishList = realm.objects(WishList.self)
let theWishList = allWishList.filter("userID CONTAINS[cd] %#", userID).first
guard let userWishList = theWishList else {return}
// 2. modify Wishlist data in Realm.
if loveIconHasBeenFilled {
guard let index = userWishList.products.index(where: {$0.productID == selectedProduct.productID}) else {return}
do {
// remove data from realm database
try realm.write {
userWishList.products.remove(at: index)
}
} catch {
// error Handling
}
} else {
do {
// add product to wishlist model in realm database
try realm.write {
userWishList.products.append(selectedProduct)
}
} catch {
// error Handling
}
}
and here is the data in Realm Browser
and the problem is ....
when I run the app for the first time, I can add, and then remove, and then add the product again to the wishlist, and the number of product in the realm database still be the same (all have unique productID)
but when I restart the app, and try to click that love button to add the product to wishlist again, it throws an error
'RLMException', reason: 'Attempting to create an object of type
'Product' with an existing primary key value 'a'
this error is triggered because of this line of code userWishList.products.append(selectedProduct) , when adding the product to WishList, it automatically adds Product in the realm database. so because I keep adding the same product that has the same productID (primary key) it will throw that error.
so, my question is, how to avoid addition in Product if it has the same productID (primary key), it is better if i can just update the product in realm database when adding the product to the wishlist using this line of code: userWishList.products.append(selectedProduct)
You could check the property hasBeenAddedToWishList of the selected product and only add it if the property is false.
if loveIconHasBeenFilled {
//your logic to remove already added products
} else if !selectedProduct.hasBeenAddedToWishList { //<--- check if the product already exists in wishlist if not you add it
do {
// add product to wishlist model in realm database
try realm.write {
userWishList.products.append(selectedProduct)
}
} catch {
// error Handling
}
}

Defining a Realm Database Structure (Swift)

I am in the process of creating an application that will display a list of stocks that a user saves in a tableView. It will also allow the user to add or remove items from their favorites. I need help defining the database structure and setting up for the adding and constant updating of the user's favorite stocks.
I currently have a StockData struct that works with my tableView and a button for adding to the user's list:
struct StockData {
let currentPrice: Double
// meta data
let name: String
let ticker: String
let interval: String
let lastRefreshed: String
let change: Double
}
// In an actual ViewController
#IBAction func addButtonClicked(_ sender: Any) {
print("Add clicked")
// Handle adding the item to the user's list
}
Now as far as my current realm model is concerned, I have:
class User: Object {
#objc dynamic var name = ""
#objc dynamic var id = ""
var stockFavs = List<StockItem>()
}
class StockItem: Object {
#objc dynamic var currentPrice: Double = 0.0
// meta data
#objc dynamic var name = ""
#objc dynamic var ticker = ""
#objc dynamic var interval = ""
#objc dynamic var lastRefreshed = ""
#objc dynamic var change: Double = 0.0
}
// Setting up the user and creating test values
let newUser = User()
newUser.name = "John Smith"
newUser.id = "coolId123"
var stockArr = List<StockItem>()
for i in 0..<12 {
let item = StockItem()
item.name = "Microsoft Corporation"
item.change = -3.55
item.currentPrice = 123.45
item.interval = "1day"
item.lastRefreshed = "Now"
item.ticker = "MSFT"
stockArr.append(item)
}
newUser.stockFavs = stockArr
try! realm.write {
realm.add(newUser)
}
So far, I have been able to create a user object for the current user of the device and add test values, but I am unsure how to implement constant realm updating (the method would have self.tableView.reloadData(), but apart from that, I'm clueless) in conjunction with the ability to add StockItem's to the user's array.
Any help would be much appreciated!
You use a function for every time you want to add to the database.
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 100)
button.addTarget(self, action: #selector(add), for: .touchUpInside)
func add() {
let currentData = [MyFakeData1, MyFakeData2, etc.]
try! realm.write {
realm.add(currentData)
}
// You need to get the updates in the database
// You could have an array in your model that you update and then append all
// the new items to it and only do database lookups when you restart the
// device
update()
}
func update() {
let realm = try! Realm()
var newArray = realm.objects(StockItem.self)
myViewController.modelArray = newArray
table.reloadData()
}

Error when user tries to send next message immediately in Realm

Here are my two realm models used to create objects in realm database.
class Users: Object {
dynamic var phoneNumber:String = ""
dynamic var messageSenderName:String = ""
let userMessages = List<Messages>()
override static func primaryKey() -> String? {
return "phoneNumber"
}
// convenience init() here
}
class Messages: Object{
dynamic var id = UUID().uuidString
dynamic var phoneNumber:String = ""
dynamic var messageSenderName:String = ""
dynamic var messageBody:String = ""
dynamic var message_id:String = ""
dynamic var messageTime:String = ""
override static func primaryKey() -> String? {
return "id"
}
// convenience init here
}
This my RosterViewController where I show the 'phoneNumber' and latest 'messageBody' in tableViewCell. I am using XMPP Framework to receive messages and SwiftyXMLParser to parse the xml messages.
class RosterViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var realm : Realm!
dynamic var users = Users()
var userResult : Results<Users>!
dynamic var messagedata = Messages()
var messageResult : Results<Messages>!
override func viewDidLoad() {
super.viewDidLoad()
realm = try! Realm()
notificationToken = realm.observe{ notification, realm in
self.contactsTableView.reloadData()
}
}
func xmppStream(_ sender: XMPPStream, didReceive message: XMPPMessage) {
.......
// parse xml and set object values here
userResult = realm.objects(Users.self)
messageResult = realm.objects(Messages.self)
try! realm.write {
users.userMessages.append(messagedata)
realm.add(users, update: true)
realm.add(messagedata, update: true)
}
}
}
}
I want to append the messages dynamically to the users List of the respective message sender. I am not able to do so. I am receiving messages in real time so they should get appended to the list and thus reflect the same on tableView.
First message is shown properly, but when same user sends another message immediately then I get an error saying:
RLMException', reason: 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first
I have also tried a lot, but could not get any fixes or workaround. Please help me solve this issue, just began with realm. Thank you!

Save User using Realm Object

I am creating a project. I want if the userID already exist, it doesn't add the user. But somehow my code isn't working properly.
This is my Realm Model Object (User.swift):
import Foundation
import RealmSwift
class User: Object {
#objc dynamic var userID = Int()
#objc dynamic var username = ""
#objc dynamic var full_name = ""
#objc dynamic var myBool = Bool()
override static func primaryKey() -> String? {
return "userID"
}
}
And this is the button to add users:
#IBAction func add(_ sender: Any) {
let myUser = User()
let JSON_userID = Int(arc4random_uniform(5)) // This is temporary. I am going to get code from JSON, but using random for testing purpose.
if (myUser.userID != JSON_userID) {
myUser.userID = JSON_userID
myUser.username = "myUsername"
myUser.full_name = "My Name"
let realm = try! Realm()
try! realm.write {
realm.add(myUser)
}
}
else {
print("Already exist")
}
}
Sometimes it runs the code, but most of the times it crashes with error:
libc++abi.dylib: terminating with uncaught exception of type NSException.
As you defined a primary key in your User object, Realm can handle this automatically if you set the update parameter to true inside the write closure.
let realm = try! Realm()
try! realm.write {
realm.add(myUser, update: true)
}
If the update parameter is not set or false, Realm will throw an exception when you try to add an object with an existing primary key.
This makes the if / else condition useless. It can be removed.
If you need to know if the user already exists, you can request the Realm with the primary key value:
realm.object(ofType: User.self, forPrimaryKey: JSON_userID)
The result will be nil if the user does not exist.

Resources