I use Xcode 9.2 with swift 4 for an IOS application
everything work nice , but when i add realm [ save to DB after click on the button ] , and then click into the button the app crush with this message
SIGNAL SIGABRT
and when i changed the realm method with just a simple methode with
print("clicked")
it works
i use this pod line to add the library
pod 'RealmSwift'
and i have the code below
floaty.addItem("Share", icon: UIImage(named: "share-variant")! , handler:{ item in
self.shareTxt()
})
floaty.addItem("Save", icon: UIImage(named: "content-save")! , handler:{ item in
self.saveToDB()
})
func saveToDB() {
let realm = try! Realm()
realm.beginWrite()
realm.create(News.self, value: [SingleItem?.id])
try! realm.commitWrite()
}
class News: Object {
#objc dynamic var new_id = ""
}
First, make the property new_id as the Primary key:
class News: Object {
#objc dynamic var new_id = ""
override static func primaryKey() -> String? {
return "new_id"
}
}
Then, add or update the model:
func saveToDB() {
if let newId = SingleItem?.id {
let realm = try! Realm()
let news = realm.objects(News.self).filter("new_id == \(newId)").first
if news != nil {
try! realm.write {
//optional, updating some fields...
//like: news.title = "some title"
}
}
else{
let news = News(value: ["new_id", newId])
try! realm.write {
realm.add(news)
}
}
}
}
Related
I have added realm integration in my app. Process is that,
1] if list is not empty then reload the tableview , and at the same time call an api, receive its response..
2] check value present against Id or not, if present delete that value from realm, again add value to realm and reload the tableview.. Code is working fine, if i wait for the 2nd step completion. But 2nd step is totally asynchronous..Here is what I have tried
And crash is happening when i change viewcontroller before the completion 2nd step.
public class Features : Object , Codable{
#objc dynamic var intellinectsId : String?
#objc dynamic var serviceName : String?
#objc dynamic var android_icon : String?
#objc dynamic var parentUrl : String?
#objc dynamic var url : String?
#objc dynamic var mobileOrder : String?
enum CodingKeys: String, CodingKey {
case serviceName = "serviceName"
case android_icon = "android_icon"
case parentUrl = "parentUrl"
case url = "url"
case mobileOrder = "mobileOrder"
case intellinectsId = "intellinectsId"
}
required convenience public init(from decoder: Decoder) throws {
self.init()
let values = try decoder.container(keyedBy: CodingKeys.self)
serviceName = try values.decodeIfPresent(String.self, forKey: .serviceName)
android_icon = try values.decodeIfPresent(String.self, forKey: .android_icon)
parentUrl = try values.decodeIfPresent(String.self, forKey: .parentUrl)
url = try values.decodeIfPresent(String.self, forKey: .url)
mobileOrder = try values.decodeIfPresent(String.self, forKey: .mobileOrder)
intellinectsId = try values.decodeIfPresent(String.self, forKey: .intellinectsId)
}
required init() {
}
}
I have created single class for RealmService
class RealmService {
private init() {}
/// To get singleton class
static let shared = RealmService()
/// To get realm object instance
var realm = try! Realm()
/// To create a record or adding new object to database
func create<T: Object>(_ object: T) {
do {
try realm.safeWrite {
//realm.add(object)
realm.create(T.self,value: object)
//realm.create(T.self, value: object, update: .modified)
}
} catch {
post(error)
}
}
/// To update/modify particular record/object in the database
func update<T: Object>(_ object: T, with dictionary: [String: Any?]) {
do {
try realm.write {
for (key, value) in dictionary {
object.setValue(value, forKey: key)
}
realm.add(object, update: .all) //add(object, update: true)
}
} catch {
post(error)
}
}
/// To delete/remove record or object database
func delete<T: Object>(_ object: T) {
do {
try realm.write {
realm.delete(object)
}
} catch {
post(error)
}
}
/// To handle the errors while performing realmDB opration
func post(_ error: Error) {
NotificationCenter.default.post(name: NSNotification.Name("RealmError"), object: error)
}
/// To observe realm error in the particular View controller
func observeErrors(in vc: UIViewController, completionHandler: #escaping(Error?) -> Void) {
NotificationCenter.default.addObserver(forName: NSNotification.Name("RealmError"), object: nil, queue: nil) { (notification) in
completionHandler(notification.object as? Error)
}
}
/// To stop observing errors in particular View Controller
func stopObservingErrors(in vc: UIViewController) {
NotificationCenter.default.removeObserver(vc, name: NSNotification.Name("RealmError"), object: nil)
}
/// To delete complete realm form the app
func completeDeleteRealm() {
let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
let realmURLs = [
realmURL,
realmURL.appendingPathExtension("lock"),
realmURL.appendingPathExtension("note"),
realmURL.appendingPathExtension("management")
]
for URL in realmURLs {
do {
try FileManager.default.removeItem(at: URL)
} catch {
post(error)
}
}
}
}
Now in View controller , I am taking a value from realm, against id, like this
var dashboardList : Results<Features>{
get{
return RealmService.shared.realm.objects(Features.self).filter(NSPredicate(format: "intellinectsId == %#", HelperFunctions().getUserInfoFromDefaults()?.intellinectsId ?? ""))
}
}
.. as given in step 1st, if dashboardList count is > 0 then reload the tableview , simultaneously , call and api to fetch the details and again I have performed 2nd step like below
if let responseList = response.array, responseList.count > 0{
//remove existing data from realm
let removeHMC = RealmService.shared.realm.objects(Features.self).filter(NSPredicate(format: "intellinectsId == %#",intellinectsId))
if let realm = try? Realm(){
try? realm.write {
realm.delete(removeHMC)
}
}
if let featuresList = responseList[0]["features"].array, featuresList.count > 0{
for val in featuresList{
let feature = Features()
feature.intellinectsId = intellinectsId
feature.serviceName = val["serviceName"].string
feature.android_icon = val["android_icon"].string
feature.parentUrl = val["parentUrl"].string
feature.url = val["url"].string
feature.mobileOrder = val["mobileOrder"].string
RealmService.shared.create(feature)
}
}
}
And if i wait for this completion then it works fine. but if i go on next vc. I am getting an error like
libc++abi.dylib: terminating with uncaught exception of type NSException
after looking at the specific issue, I received an error
Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
I applied this trick also.. But after deleting value from realm , showing again to the tableview causes this issue. I am unable to figure out. Kindly help
In your response when you are deleting the previous features list you are creating a new instance of Realm() which will cause inconsistencies between those two.
Try removing that and using the same RealmService.shared like this
//remove existing data from realm
let removeHMC = RealmService.shared.realm.objects(Features.self).filter(NSPredicate(format: "intellinectsId == %#",intellinectsId))
RealmService.shared.delete(removeHMC)
I have products in my Realm database like this
I want to update my realm database based on productID, so I don't need to add another product over and over again. let say I want to update quantity of product that has productID = "a" to be 5.
I have tried to write something like this.
let selectedProductID = "a"
let productsInRealmDatabase = realm.objects(Product.self)
let productIndex = productsInRealmDatabase.index(where: {$0.productID == selectedProductID})
if let productIndex = productIndex {
do {
try realm.write {
var productRealm = productsInRealmDatabase[productIndex]
productRealm.quantity = 5
productsInRealmDatabase[productIndex] = productRealm // ERROR HERE
}
} catch {
// error Handling
}
}
but I got error in : productsInRealmDatabase[productIndex] = productRealm
Error Message: Cannot assign through subscript: subscript is get-only
so how to update realm object based on the certain property in Realm?
You should use Realm's own filter method which accepts an NSPredicate and returns an auto-updating Results instance rather than Swift's filter when operating on Realm collections. Than either update the properties of the fetched prouduct or create a new one and save that to Realm.
let selectedProductID = "a"
let productsInRealmDatabase = realm.objects(Product.self)
let matchingProduct = productsInRealmDatabase.filter("productID == %#", selectedProductID).first
if let matchingProduct = matchingProduct {
do {
try realm.write {
matchingProduct.quantity = 5
}
} catch {
// error Handling
}
} else {
let newProduct = Product()
newProduct.productID = selectedProductID
newProduct.quantity = 5
do {
try realm.write {
realm.add(newProduct)
}
} catch {
// error Handling
}
}
If you want your Products to be unique based on their productID property, you use also set productID as the primaryKey of your Object subclass.
class Product:Object {
#objc dynamic var productID = ""
...
override static func primaryKey() -> String? {
return "productID"
}
}
Try this -
let selectedProductID = "a"
let productsInRealmDatabase = realm.objects(Product.self)
let filteredProducts = productsInRealmDatabase.filter("productID = \(selectedProductID)")
do {
try realm.write {
filteredProducts.forEach { product in
product.quantity = 5
}
}
} catch {
// error Handling
}
While inserting data to your database inside the insert function mark update key as true and then try updating the value. eg:
static func insertData() {
//Your insertion code//
try! realm.write {
realm.add(request, update: true)
}
}
static func updateData(productId: String, quantity: Int) {
let product = self.getProductData(prodId: productId)
let realm = try! Realm()
try! realm.write {
product?.quantity = quantity
}
}
Hope this helps you out.
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)
}
}
I am trying to save a simple object with Realm but the app keeps crashing when trying to make a write transaction even when it's wrapped in a Do Catch block.
let theme = Theme()
theme.name = "Custom Theme"
theme.backgroundColor = backgroundColor
theme.accentColor = accentColor
theme.numberColor = numColor
theme.functionColor = funcColor
// Add to the Realm inside a transaction
do {
try Realm().write {
do {
try Realm().add(theme, update: true)
} catch {
print("Error saving data")
}
}
} catch {
print("Realm.write error")
}
Here is the object 'Theme'
class Theme : Object {
dynamic var name = ""
dynamic var backgroundColor = ""
dynamic var accentColor = ""
dynamic var numberColor = ""
dynamic var functionColor = ""
override static func primaryKey() -> String? {
return "name"
}
}
Here is a screenshot of the crash
SIGABRT Crash
EDIT: The code above that causes the crash is only executed when a button is clicked. There is no console output either. I am bringing realm in via CocoaPods.
Ah, it might have something to do with the way you're creating the realm instances, try this:
let realm = try! Realm()
do {
try realm.write {
do {
try realm.add(theme, update: true)
} catch {
print("Error saving data")
}
}
} catch {
print("Realm.write error")
}
Though, usually you won't need to wrap your transactions into a do-catch block:
let realm = try! Realm()
try! realm.write {
realm.add(theme, update: true)
}
I'm not sure how to save a title from a textfield into Realm. CurrentNote and note are both from Note, a swift file with dynamic vars including title.
func saveNote() {
currentNote = Note()
note = currentNote
if let note = note {
let realm = Realm()
var index = tableView[]
var changingNote:Note = Note()
changingNote.title = index
realm.write{
realm.add(note)
self.notes = realm.objects(Note)
}
}
tableView.reloadData()
}
Could something like the following work?
func saveNote(noteIndex: Int) {
let note = notes[noteIndex]
note.realm.write {
note.title = TITLE
}
}