How to set primary key in Swift for Realm model - ios

I'm using Realm in a new iOS Swift project. I'm using Xcode 6.0.1 with iOS SDK 8.0 and Realm 0.85.0
I'm trying to use the new Realm primary key feature so I can do an addOrUpdateObject.
Here is a sample model:
import Foundation
import Realm
class Foo: RLMObject {
dynamic var id = 0
dynamic var title = ""
func primaryKey() -> Int {
return id
}
}
And how I'm trying to add/update a new object:
let foo = Foo()
foo.title = titleField.text
foo.id = 1
// Get the default Realm
let realm = RLMRealm.defaultRealm()
// Add to the Realm inside a transaction
realm.beginWriteTransaction()
realm.addOrUpdateObject(foo)
realm.commitWriteTransaction()
I get this error:
RLMExecption', reason: ''Foo' does not have a primary key and can not
be updated
Here are the docs on the primary key. I'm probably not setting it correctly:
http://realm.io/docs/cocoa/0.85.0/api/Classes/RLMObject.html#//api/name/primaryKey
Latest docs are here now:
https://realm.io/docs/objc/latest/api/Classes/RLMObject.html#//api/name/primaryKey

As of Realm Swift v10.10.0, you declare a primary key with #Persisted(primaryKey: true):
class Foo: Object {
#Persisted(primaryKey: true) var id = 0
#Persisted var title = ""
}
Older versions:
primaryKey needs to be a class function which returns the name of the property which is the primary key, not an instance method which returns the value of the primary key.
#objcMembers class Foo: RLMObject {
dynamic var id = 0
dynamic var title = ""
override class func primaryKey() -> String? {
return "id"
}
}

The return type of primaryKey() is optional:
class Foo: RLMObject {
dynamic var id = 0
dynamic var title = ""
override class func primaryKey() -> String? {
return "id"
}
}

For Swift 5:
import RealmSwift
class Signature: Object {
#objc dynamic var id = ""
override static func primaryKey() -> String? {
return "id"
}
}
To avoid: Terminating app due to uncaught exception 'RLMException', reason: 'Primary key property 'id' does not exist on object.

Realm 10.12.0 & Swift 5
Legacy property declarations using #objc:
import RealmSwift
class Signature: Object {
#objc dynamic var id = ""
override static func primaryKey() -> String? {
return "id"
}
}
When using #Persisted, use #Persisted(primaryKey: true) instead:
import Foundation
import RealmSwift
class MyModel: Object {
#Persisted var pan: String?
#Persisted var exp: String?
#Persisted var cvv: String?
#Persisted(primaryKey: true) var myId: String?
override init() {}
init(pan: String, exp: String, cvv2: String) {
super.init()
self.pan = pan
self.exp = exp
self.cvv = cvv2
}
}

Related

How to make search query to get all Objects in Realm

I am creating a Realm object like below
import RealmSwift
class Item: Object {
#objc dynamic var ID = 0
#objc dynamic var notificationTitleString = ""
#objc dynamic var notificationBodyString = ""
#objc dynamic var notificationDateString = ""
#objc dynamic var notificationType = ""
#objc dynamic var notificationUrl = ""
#objc dynamic var notificationActivity = ""
#objc dynamic var notificationIsRead = ""
override static func primaryKey() -> String? {
return "ID"
}
}
I am using the below method to get a particular item type
import UIKit
import RealmSwift
class DBManager {
private var database: Realm
static let sharedInstance = DBManager()
private init() {
database = try! Realm()
print(Realm.Configuration.defaultConfiguration.fileURL!)
}
func fetchNotificationType(type: String) -> Results<Item> {
let predicate = NSPredicate(format: "notificationType = %#", type)
let results : Results = database.objects(Item.self).filter(predicate)
return results
}
}
Using the above fetchNotificationType method i am able to get a single object, But i want all the objects in a single query. I do not know how to do that, I am trying Realm for the first time.
I searched SO, but i did not get any related answers.

Adding a new relationship to an existing model in Realm

I'm developing an iOS application using Realm and have a object MedicationObject which contains the information about the Medication being used. This then has a many to one relationship class MedicationRecording which stores the information when the time the medication was taken.
import Foundation
import RealmSwift
class MedicationObject : Object {
//This model requires a Primary Key
#objc dynamic var id = 0
override static func primaryKey() -> String? {
return "id"
}
#objc dynamic var medicationName : String = ""
//stores the refrences to medication recoridngs
var messurements = List<MedicationRecording>()
public func addNewMesurment() {
print(self)
let medicationRecording = MedicationRecording()
medicationRecording.medicationTaken = self
medicationRecording.timeTaken = Date()// this saves the time to now
medicationRecording.medicationTaken = self
RealmAccess().updateMedicationObject(medicationObject: self, medicationRecord: medicationRecording) //this should work
}
}
here is my MedicationRecording:
import Foundation
import RealmSwift
class MedicationRecording : Object {
#objc dynamic var medicationTaken : MedicationObject? = MedicationObject()
#objc dynamic var timeTaken : Date = Date()
#objc dynamic var id = 0
override static func primaryKey() -> String? {
return "id"
}
}
and this is the method I'm calling to save the data to
func updateMedicationObject(medicationObject : MedicationObject, medicationRecord : MedicationRecording) {
let realm = try! getRealmAccess()
let mediObject = MedicationObject()
mediObject.medicationName = medicationObject.medicationName
do {
try! realm.write {
realm.add(medicationRecord, update: true)
medicationObject.messurements.append(medicationRecord)
}
}
}
At the moment when I'm saving the data it is then losing all the information in MedicationObject and only saving the last data.
Any help with be greatly appreciated
Thank you

EVReflection + Moya + Realm + RxSwift - Could not create an instance for type dict

I'm stuck putting all of the above together. I'll appreciate if I can get any input.
Here's my short setup:
typealias RealmObject = Object
/// Extension to ignore undefined keys when mapping
extension RealmObject : EVReflectable {
open override func setValue(_ value: Any?, forUndefinedKey key: String) { }
}
Sample Realm models:
class Product: RealmObject {
dynamic var productId: String = ""
let productLanguages = List<ProductLanguage>()
override static func primaryKey() -> String? {
return "productId"
}
}
class ProductLanguage: RealmObject {
dynamic var productLanguageId: String = ""
dynamic var languageCode: String = ""
dynamic var productName: String = ""
override static func primaryKey() -> String? {
return "productLanguageId"
}
}
To fetch product details I use Moya and RxSwift:
func getProduct(productItemKey: String) -> Observable<Product> {
return provider.request(.product(productId: productItemKey)).map(to: Product.self)
}
I think .map(to: Product.self) does not work with realm Lists out of the box. For each object inside the list I get an error:
ERROR: Could not create an instance for type
dict:{
CreateDate = "2015-10-12T11:11:50.013Z";
IngredientList = "Acao ingredient";
LanguageCode = "en-US";
ProductId = "d6bb0084-6838-11e5-9225-00ac14ef2300";
ProductLanguageId = "f96848d0-df77-4594-99b7-d390bb127891";
ProductName = Acao;
Tagline = "The smart drink - 100% organic, vegan energy booster with guara"
}
Is there any other way to map Moya response into Realm objects?
Thank you very much for any input!
Turns out it was a bug in EVReflection. Fixed in 4.17.0

Many-to-one with primary key (unique constraint)

I've got an Article and a Category model linked by a many-to-one relationship. However, the Category model has a unique constraint on the id property because it's the primary key as you can see below.
class Article: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var category: Category()
override static func primaryKey() -> String? {
return "id"
}
}
class Category: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
This will work until an Article got the same Category and throw an exception because of the unique constraint.
How am I supposed to implement this kind of relationship ? Is there any built-in way to persist only the Category id and retrieve the corresponding Category ?
Thanks
As you can read in Realm doc (0.92.1), you have to use a List<Object> for a many-to-one relationship.
See this link :
http://realm.io/docs/swift/latest/
class Dog: Object {
dynamic var name = ""
dynamic var owner: Person? // Can be optional
}
class Person: Object {
... // other property declarations
let dogs = List<Dog>()
}
let someDogs = Realm().objects(Dog).filter("name contains 'Fido'")
jim.dogs.extend(someDogs)
jim.dogs.append(rex)
So in your case, I guess it should be something like that :
class Article: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
class Category: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var articles = List<Article>()
override static func primaryKey() -> String? {
return "id"
}
}
If your Realm version is older :
class Category: Object
{
...
dynamic var categories = RLMArray(objectClassName: Article.className())
}

How to create custom initilizers with Cocoa Realm

I have a swift project with Realm in it where I would like to store objects using RLMObject, however I cannot create a custom init, as it will throw an error.
I Have tried
import Foundation
import Realm
class Foo: RLMObject {
dynamic var First: String = ""
dynamic var Last: String = ""
init(first: String, last: String) {
super.init()
self.First = first
self.Last = last
}
override init(object: AnyObject?) {
super.init(object:object)
}
override init(object value: AnyObject!, schema: RLMSchema!) {
super.init(object: value, schema: schema)
}
override init(objectSchema: RLMObjectSchema) {
super.init(objectSchema: objectSchema)
}
}
Which was suggested here

Resources