I am new to Realm and I am wondering if it is good idea to store primary key of object in View controller and object as stored property.
class VC: ViewController{
public var id:Int!
private var customer:Customer{
get{
return DBO.loadCustomer(for: id)
}
}
}
class DBO{
public static func loadCustomer(for id: Int) -> Customer{
let realm = try! Realm()
return realm.object(ofType: Customer.self, forPrimaryKey: id)!
}
}
I am assuming that this because of this my app will be thread safe, because every time thread will try to access customer it will fetch object from db. But I wonder if this is efficient for single object and array of objects.
As of Realm 2.2 you could use thread-safe references (see here):
Now, you can create thread-safe references for all types that were
previously thread-confined within a Realm, and passing objects between
threads becomes a simple, three-step process:
Initialize a ThreadSafeReference with the thread-confined object.
Pass that ThreadSafeReference to a destination thread or queue.
Resolve this reference on the target Realm by calling
Realm.resolve(_:). Use the returned object as you normally would.
And a code sample, from the source above:
let realm = try! Realm()
let person = Person(name: "Jane") // no primary key required
try! realm.write {
realm.add(person)
}
let personRef = ThreadSafeReference(to: person)
DispatchQueue(label: "com.example.myApp.bg").async {
let realm = try! Realm()
guard let person = realm.resolve(personRef) else {
return // person was deleted
}
try! realm.write {
person.name = "Jane Doe"
}
}
But, your approach should also work fine.
Related
I want to make an offline translator (dictionary) with swift 4.
I need advice on where to store words with translation.
The words with the translation are now in the dsl format and I search for this particular file, but on average it takes 2-3 seconds to search.
Is it possible to speed up the search? If i put words with translation in core data or realm database, its help or not ?
Realm Swift enables you to efficiently write your app’s model layer in a safe, persisted and fast way. Here’s what it looks like:
// Define your models like regular Swift classes
class Dog: Object {
#objc dynamic var name = ""
#objc dynamic var age = 0
}
class Person: Object {
#objc dynamic var name = ""
#objc dynamic var picture: Data? = nil // optionals supported
let dogs = List<Dog>()
}
// Use them like regular Swift objects
let myDog = Dog()
myDog.name = "Rex"
myDog.age = 1
print("name of dog: \(myDog.name)")
// Get the default Realm
let realm = try! Realm()
// Query Realm for all dogs less than 2 years old
let puppies = realm.objects(Dog.self).filter("age < 2")
puppies.count // => 0 because no dogs have been added to the Realm yet
// Persist your data easily
try! realm.write {
realm.add(myDog)
}
// Queries are updated in realtime
puppies.count // => 1
// Query and update from any thread
DispatchQueue(label: "background").async {
autoreleasepool {
let realm = try! Realm()
let theDog = realm.objects(Dog.self).filter("age == 1").first
try! realm.write {
theDog!.age = 3
}
}
}
For a dictionary app. I'd definitely go with Realm. it uses NSFileProtection and encryption so people won't be able to steal your translation data.
Setup RealmSwift for your projects
I have 3 realm model classes, say ModelA, ModelB, ModelC. All 3 of these models have a param name fav.
In my method, I want to fetch the model object (which can be of any of the above 3 types) and update the fav param based on API response.
enum ModelType {
case ModelA
case ModelB
case ModelC
}
func update(type: ModelType, id: Int) {
let realm = try Realm()
if let model = realm?.object(ofType: Object.self, forPrimaryKey: id) {
do {
try realm?.write {
let favourite = FavModel()
model.favourite = favourite
realm?.add(model, update: true)
}
} catch {}
return model
}
return nil
}
I have an enum which can tell me what kind of model object is it, but not sure how to specify the class name while fetching realm objects realm?.object(ofType: Object.self, for the primary key: id).
The Object.self should be either ModelA.self, ModelB.self, or ModelC.self.
You don't need to use ModelType to store your class names in enum. Instead, you can use generics, that will make your code shorter and simpler.
I suppose that three of these classes has the same parameter because they conform to some protocol or they are inherited from some super-class that has this parameter. If it's a super-class, let say its name is SuperModel. In that case, your method should look like that
func update<StoredType: SuperModel>(type: StoredType.Type, id: Int) {
let realm = try? Realm()
if let model = realm?.object(ofType: type, forPrimaryKey: id) {
// handle your model
}
return nil
}
If your model classes conform to some protocol (let say it's named is ModelProtocol) then your method should look like that.
func update<StoredType: Object & ModelProtocol>(type: StoredType.Type, id: Int) {
let realm = try? Realm()
if let model = realm?.object(ofType: type, forPrimaryKey: id) {
// handle your model
}
return nil
}
With that you can simply call this method, passing your model type as a parameter
update(type: ModelA.self, id: 1)
I am new to iOS developing. I try to receive the data which is stored in realm Database but sometimes I get an empty set although I can see the data in RealmBrowser. Often it works, but it is not reliable.
At first I clear the stored data to get sure I am not going to display old data.
After that I insert it to the RealmDatabase and in addition to that I query all stored data to display it in the tableView.
Here is my code (Swift 3):
let realm = try! Realm()
try! realm.write {
// clear all old data stored as fahrt.self
//realm.delete(realm.objects(fahrt.self));
realm.delete(realm.objects(fahrt.self));
let nsArray = try! JSONSerialization.jsonObject(with: data as Data, options: []) as! NSArray;
for eintrag in nsArray{
realm.create(fahrt.self, value: eintrag, update: false)
}
try! realm.commitWrite();
}
DispatchQueue.main.async {
let temp = ui as! DisplayViewController;
let realm = try! Realm()
let result = realm.objects(fahrt.self)
ui.showData(res: result);
// sometimes result is empty , don't know why
}
RealmModel:
class fahrt: Object {
dynamic var id: Int = 0
dynamic var date = ""
dynamic var from_lang: Double = 0.0
dynamic var from_lon: Double = 0.0
dynamic var to_lang: Double = 0.0
dynamic var to_lon: Double = 0.0
override static func primaryKey() -> String? {
return "id"
}
}
First of all, you don't need to include realm.commitWrite() inside a realm.write { } block. realm.commitWrite() is used in conjunction with realm.beginWrite(), but both of these are automatically called inside realm.write { }. :)
Secondly, when you perform a write transaction on a background thread, the changes are automatically exposed on the main thread on the next iteration of the run loop. However, in some cases, when immediately calling code on the main thread after a background write, it's possible this hasn't happened yet. To ensure Realm has the very latest copy of its data on the main thread, you should call realm.refresh() in that dispatch block before you perform the query.
Is running a query the only way of re-initializing a Realm Object for use in a different thread? Is there no way to somehow grab some kind of reference for use with Realm, so that the query doesn't have to be completely from scratch? It would be nice to have some kind of guarantee that the object is for the same record (if it exists and the query for that "ref" is successful), without having to add a primary key just for this one purpose.
This outlines my situation:
func construct(name: String, tokens: [String]) -> Document {
let doc = Document()
let realm = try! Realm()
try! realm.write {
realm.add(doc)
}
DispatchQueue.global(qos: .userInitiated).async {
let realm = try! Realm()
// Some long running task to convert `tokens` into `[Blurb]`
// var blurbs: [Blurb]
// What's the recommended way of re-initing that new `Document`?
// let sameDoc = .....
try! realm.write {
sameDoc.blurbs.append(blurbs)
}
}
return doc
}
the Problem is, that I can add relationships to my object and it works temporally but realm doesn't save the changes and when I quit the app and restart ist, the relationships are gone.
In the first view I create the main object. Here is the class:
class UserListClass: Object {
dynamic var UserListName = ""
let Medis = List<MediClass>()
override static func primaryKey() -> String? {
return "UserListName"
}
}
And the code how I create the object:
let realm = try! Realm()
let newList = UserListClass ()
newList.UserListName = textField.text!
try! realm.write {
realm.add(newList)
}
This works without problems, and the object I add is also there when I restart the app.
When the user click on Edit it will open the next view:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showUserlistEdit" {
let editViewController = segue.destinationViewController as! MediUserlistEditViewController
editViewController.userlist = userlist
}
}
In the next view the code add selected entries to the list, I tried two versions, but both have the result, that it saves the relationships only for the runtime of the app. When I restart it, they are away.
First try:
let realm = try! Realm()
try! realm.write {
userlist.Medis.append(medi)
realm.add(userlist, update: true)
}
Second try:
let realm = try! Realm()
try! realm.write {
userlist.Medis.append(medi)
}
The problem is the
let realm = try! Realm()
The documentation specify
// Get the default Realm
let realm = try! Realm()
// You only need to do this once (per thread)
You did on both view controllers and there is no guarantee that the path to the default Realm will be the same. It might work on the actual device but not on simulator.
Try this and delete all other occurrences
// Put this inside your Real class Definition/Declaration file
let realm = try! Realm()
Hope this help