How to know whether a Realm object was successfully updated? - ios

I am using Realm mobile database. I update Realm objects using the following code. I want to get a callback with whether or not that Realm object was successfully updated.
do {
let realm = try Realm()
realm.beginWrite()
if let Settings = realm.objects(ModelClass).first {
Settings.settingsVal = settingsValue
realm.add(Settings, update: true)
}
try realm.commitWrite()
}
catch {
}

There are a number of different ways to achieve what you are looking to do, including using closures/delegates to provide a callback mechanism, however the simplest way to know that the update was successful would be to add code inside the try block:
do {
let realm = try Realm()
realm.beginWrite()
if let Settings = realm.objects(ModelClass).first {
Settings.settingsVal = settingsValue
realm.add(Settings, update: true)
}
try realm.commitWrite()
print("Success")
}
catch{
}
}

Related

Auto login using UserDefaults() not working Swift 5

I have followed some tutorials and used their methods to implement auto login for my app, but once I relaunch the app after entering the credentials, the app does not log in.
var userDefaults = UserDefaults.standard
here I initiate the user defaults feature
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let safeData = data {
if let dataString = String(data: safeData, encoding: String.Encoding.utf8) {
print(dataString)
if dataString == "Hello" {
self.userDefaults.setValue(true, forKey: "UserIsLoggedIn")
DispatchQueue.main.async {
self.performSegue(withIdentifier: "loginSegue", sender: self)
}
} else {
DispatchQueue.main.async {
self.validationLabel.isHidden = false
self.validationLabel.text = " Username or password is incorrect. "
self.loginSuccessful = false
}
}
}
} else {
print(error ?? "Error with data API URLSession")
}
}.resume()
here, inside the API call. if the response from the API is "hello" which means the login was successful, i set the value to true with an identifier.
if userDefaults.value(forKey: "UserIsLoggedIn") as? Bool == true {
performSegue(withIdentifier: "loginSegue", sender: self)
} else {}
here in the view did load I use the userDefaults to perform the segue to the next screen for future launches.. but it is not working.
initiation
viewdidload
API call
var userDefaults = UserDefaults() seems wrong. Use let userDefaults = UserDefaults.standard instead. Also there's no need to make this a property of your class, simply use this within your methods whereever it's needed.
Swift 5. Auto login myApplication According woking & help you best my try
//First Time key
// According API Response success then add
if !UserDefaults.standard.bool(forKey:"isLogin") { // Success
UserDefaults.standard.set(true, forKey: "isLogin") // To do....
UserDefaults.standard.synchronize()
} else { // response fail
// To do ....
}
Have you checked if the value is being saved in your User Defaults file? If you are running your app on the simulator, try printing the file path to your User Defaults file and try locating it. It might not fix your immediate problem but it will hopefully give you an idea as to where the problem is coming from.
Try printing the location of your User Defaults file using the following line in your AppDelegate.swift
print(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as String)

I want to thread data read from realm in iOS

Reading data from ios to realm and using threads at the same time
But "Realm accessed from incorrect thread." An error occurs
Is there a problem with your code?
let realm = try! Realm()
let readData = realm.objects(DataRealm.self)
for i in 0...readData.count-1 {
DispatchQueue.global().async {
self.parsing()
}
}
You cannot use Realm objects across threads. That's why you get this error.
But you can use references which you can pass across them.
I am not sure how to apply it to your code since there is no part where you use the individual objects from readData. But what you are searching for might be something like this:
let realm = try! Realm()
let readData = realm.objects(DataRealm.self)
for data in readData {
let readDataRef = ThreadSafeReference(to: data)
DispatchQueue.global().async {
self.parsing(readDataReference: readDataRef)
}
}
In your parsing() method you would need to get the object from the reference then:
let data = realm.resolve(readDataReference)

Realm file management

We have been using Realm for a while and some of our users have been experiencing some data loss related to Realm. We think we have narrowed it down to our compaction method for when the file gets too big. We would like to ask for a little advice on if this is the proper way to recreate our Realm file. This method is called on applicationDidEnterBackground.
We wrote a sample of what we are doing below:
public static func compact() {
// Get the original file path
let configuration = RealmSampleClient.shared.config
guard let originalFileURL = configuration.fileURL else {
return
}
// check if the file size is bigger than 10mb, if not return
guard let attr = try? FileManager.default.attributesOfItem(atPath: originalFileURL.absoluteString),
let fileSize = attr[FileAttributeKey.size] as? UInt64,
fileSize > 500_000_000 else {
return
}
// create a filepath for a copy
let date = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMddHHmmss"
let dateString = "\(dateFormatter.string(from: date)).realm"
let copyFileURL = originalFileURL.deletingLastPathComponent().appendingPathComponent(dateString)
// copy the Realm file
do {
let realm = try Realm(configuration: configuration)
try realm.writeCopy(toFile: copyFileURL, encryptionKey: configuration.encryptionKey)
} catch {
return
}
// remove the old file and copy the new one
do {
removeRealmFile(at: originalFileURL)
try FileManager.default.copyItem(at: copyFileURL, to: originalFileURL)
} catch {
}
// remove a copy if it exists
guard FileManager.default.fileExists(atPath: copyFileURL.path) else { return }
do {
try FileManager.default.removeItem(at: copyFileURL)
} catch {
}
}
private static func removeRealmFile(at url: URL = databaseUrl) {
let realmURLs = [
url,
url.appendingPathExtension("lock"),
url.appendingPathExtension("note"),
url.appendingPathExtension("management"),
]
realmURLs.forEach { URL in
guard FileManager.default.fileExists(atPath: URL.path) else { return }
do {
try FileManager.default.removeItem(at: URL)
} catch {
}
}
}
Thanks your your help
I can see no kind of compacting code here, only a copy of the database file. So I assume you have left that out to keep the code compact here.
Anyway, you do this operation when the app enters background mode. Do you register a background task for that? If the compacting operation takes too much time the task gets killed by iOS, I think this is the problem.
You can explicitly ask the OS for more background execution time with UIApplication.shared.beginBackgroundTask but this is also a very time limited amount, usually 3 minutes.
But this is all digging in the dark, you should post more code to see how your background task is set up.
As per Realm doc, it's recommended to wrap your code with autoreleasepool, like this
do {
let realm = try Realm(configuration: configuration)
try realm.writeCopy(toFile: copyFileURL, encryptionKey: configuration.encryptionKey)
} catch {
return
}
and doing this in a backgroundtask will definitely help, a friendly advice is to always handle errors, you are just returning in the catch block, a log may help ..
Looking more into the doc I can see that RealmSwift integrates a compacting feature now, more details here :
https://realm.io/docs/swift/latest/#compacting-realms
We refactored the flow of our app a bit and it has seemed to solve our problems. It was related to accessing realm too soon during the startup process, possible on multiple threads.

Core Data: Constraints are conflicting even after deleting all data

Constraints are conflicting even after deleting all data.
I added unique id constraint for my entities in core data.
It works fine if app is newly installed & insert data.
but when I try to insert more data after sometime then it is not inserted.
I also tried with delete all data from db &re-insert new one, but still not working.
MY try
func saveContext () {
let context = persistentContainer.viewContext
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy //May be this creating problem
if context.hasChanges {
do {
try context.save()
} catch {
}
}
func DeleteAllData() {
for entity in ["entity1","entity2","entity3"] {
// Create Fetch Request
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entity)
// Create Batch Delete Request
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try appDelegate.persistentContainer.viewContext.execute(batchDeleteRequest)
} catch {
// Error Handling
}
}
}
Thanks for your time

Realm.io deleting many objects takes too long

I have stored some chat data in realm, where I added > 40k objects for performance tests. The querying is fast, but the deleting takes too long and freezes the UI:
static func deleteMessagesForChatId(chatId: String) {
dispatch_async(dispatch_queue_create("background", nil)) {
let realm = try! Realm()
let realmChatMessages = realm.objects(RealmChatMessage).filter("chatId = '\(chatId)'")
try! realm.write {
realm.delete(realmChatMessages)
print("message deleted from realm")
}
}
}
Instead of try! realm.write try using:
realm.beginWrite()
realm.delete(realmChatMessages)
try! realm.commitWrite()

Resources