Generic class 'SyncObject' requires that 'String' inherit from 'RealmSwiftObject' - ios

I am using IceCream Library and want to achieve the following functionality.
In app delegate, I have written
syncEngine = SyncEngine(objects: [
SyncObject(type: Recipient.self, uListElementType: String.self),
SyncObject(type: SMSSchedule.self, uListElementType: Recipient.self),
SyncObject(type: Template.self),
SyncObject(type: ContactsGroup.self, uListElementType: Recipient.self)
])
where Recipient class is...
#objc class Recipient: Object {
#objc dynamic var rec_id = ""
#objc dynamic var firstName = ""
#objc dynamic var lastName = ""
var phoneNumbers = List<String>()
#objc dynamic var email = ""
#objc dynamic var colorTag = "#FFFFFFFF"
#objc dynamic var isDeleted = false // IceCream requirement
override static func primaryKey() -> String? {
return "rec_id"
}
// initialization code
}
Look at the phoneNumbers property. It is a list of string objects. However the SyncObject doesn't accept String as uListElementType. How can I solve this issue?

Related

Separate Realm SWIFT data into lists -- and bring data back together?

So, I am a COMPLETE newbie, learning by doing real hands-on projects. I am attempting to create an app that can keep track of car parts. I'm trying to use Realm Database. In order to be organized, I'd like to keep everything separated by key bunches: "partInfo", "storeInfo", and "mechanicInfo" and then bring this back together again with the list feature of realm. Please see my code below and tell help me learn how to go about it? Thanks in advance!
I'm also trying to do MVC pattern--not sure if I did this right by separating everything out or not.
Here's my code for storeinfo.swift
import Foundation
import RealmSwift
class StoreInfo: Object {
#objc dynamic var _id = ObjectId.generate()
#objc dynamic var storeName: String = ""
#objc dynamic var storeNumber: String? = ""
#objc dynamic var storeAddress: String = ""
var catalog = LinkingObjects(fromType: Catalog.self, property: "stores")
//var itemImgs = List<String>()
override static func primaryKey() -> String? {
return "_id"
}
}
Here's my code for partinfo.swift
import Foundation
import RealmSwift
class PartInfo: Object {
#objc dynamic var _id = ObjectId.generate()
#objc dynamic var partName: String = ""
#objc dynamic var partNumber: String = ""
#objc dynamic var partDescription: String? = ""
#objc dynamic var partCost: Double = 0.00
#objc dynamic var partQuantity: Int = 0
#objc dynamic var purchaseDate: String = ""
#objc dynamic var hasWarranty: Bool = true
#objc dynamic var warrantyLength: String? = ""
var catalog = LinkingObjects(fromType: Catalog.self, property: "parts")
//var itemImgs = List<String>()
override static func primaryKey() -> String? {
return "_id"
}
}
here's my code for mechanicinfo.swift
import Foundation
import RealmSwift
class MechanicInfo: Object {
#objc dynamic var _id = ObjectId.generate()
#objc dynamic var mechanicName: String = ""
#objc dynamic var mechanicNumber: String = ""
#objc dynamic var mechanicAddress: String? = ""
#objc dynamic var mechanicCost: Double = 0.00
#objc dynamic var serviceDate: String = ""
var catalog = LinkingObjects(fromType: Catalog.self, property: "mechanics")
//var itemImgs = List<String>()
override static func primaryKey() -> String? {
return "_id"
}
}
and finally (where I'm stuck at) -- the code for Catalog.swift
import Foundation
import RealmSwift
class Catalog: Object {
#objc dynamic var _id = ObjectId.generate()
var parts = RealmSwift.List<PartInfo>()
var stores = RealmSwift.List<StoreInfo>()
var mechanics = RealmSwift.List<MechanicInfo>()
//var itemImgs = List<String>()
override static func primaryKey() -> String? {
return "_id"
}
when I go to try to use it, I'm getting an error of already using the same name. can't use it twice: (so I had to do 3 instances of wipers, which works, but it's not what I wanted...please help!)
My ViewController:
import UIKit
import RealmSwift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let realm = try! Realm()
print(Realm.Configuration.defaultConfiguration.fileURL!)
let wipers = PartInfo()
wipers.partName = "TRICO HD 32 Inch Wiper Blades"
wipers.partNumber = "67-324"
wipers.hasWarranty = true
wipers.warrantyLength = "2 years"
wipers.purchaseDate = "04/21/2021"
wipers.partCost = 34.99
wipers.partQuantity = 2
wipers.partDescription = "Great set. Lifespan of 6 - 9 months."
let wipers2 = StoreInfo()
wipers2.storeName = "O'Reilly AutoParts"
wipers2.storeAddress = "1003 W Broad St, Groveland, FL 34736"
wipers2.storeNumber = "4474"
let wipers3 = MechanicInfo()
wipers3.serviceDate = "04/24/2021"
wipers3.mechanicAddress = "17605 Sunshine Circle, Winter Garden, FL, 34787"
wipers3.mechanicCost = 289.58
wipers3.mechanicName = "Bob Barnicles"
wipers3.mechanicNumber = "353-256-7893"
try! realm.write {
realm.add(wipers)
realm.add(wipers2)
realm.add(wipers3)
}
}
}

Query on Inner and Outer object at same time Realm Swift

I have two objects ConversationModel and MessageModel as follows
class ConversationModel: Object, NSCoding {
#objc dynamic var conversation_id : String?
#objc dynamic var display_name : String?
#objc dynamic var to_jid : String?
#objc dynamic var from_jid : String?
#objc dynamic var unread_count : Int = 0
#objc dynamic var last_timestamp : String?
#objc dynamic var group_name : String?
#objc dynamic var group_id : String?
#objc dynamic var ghost_name : String?
#objc dynamic var ghost_password : String?
#objc dynamic var ghost_message : String?
#objc dynamic var user_profile_image : String?
#objc dynamic var last_message_status : String?
#objc dynamic var m_body : String?
#objc dynamic var sender_timestamp : String?
#objc dynamic var m_type : String?
#objc dynamic var receiver_timestamp : String?
#objc dynamic var userCustomProfileImageUrl: String?
#objc dynamic var profileImageUrl: String?
#objc dynamic var userImageHashKey: String?
#objc dynamic var userImageBase64String : String?
#objc dynamic var sender_jid : String?
#objc dynamic var reciever_jid: String?
#objc dynamic var sending_status: String?
#objc dynamic var is_blocked : Bool = false
#objc dynamic var is_business : Bool = false
#objc dynamic var is_ghost_enable : Bool = false
#objc dynamic var is_deleted : Bool = false
#objc dynamic var is_offline : Bool = false
#objc dynamic var is_archive : Bool = false
#objc dynamic var is_group : Bool = false
#objc dynamic var is_pin : Bool = false
#objc dynamic var is_mute : Bool = false
#objc dynamic var mute_time : String?
#objc dynamic var dataForImage : Data?
#objc dynamic var phoneNumber: String?
#objc dynamic var is_removed: Bool = false
#objc dynamic var audio_playedtime :String?
#objc dynamic var userThumbnailImage : String?
var messagesList = List<MessageModel>()
}
And Message Model is
class MessageModel: Object, NSCoding {
#objc dynamic var burning_msg_timestamp: String?
#objc dynamic var is_burning_msg : Int = 0
#objc dynamic var delivered_timestamp: String?
#objc dynamic var read_timestamp: String?
#objc dynamic var message_id: String?
#objc dynamic var reciever_id: String?
#objc dynamic var conversation_id: String?
#objc dynamic var body: String?
#objc dynamic var url: String?
#objc dynamic var sender_timestamp: CLong = 0
#objc dynamic var receiver_timestamp: String?
#objc dynamic var forward_tag: Int = 0
#objc dynamic var message_type: String?
#objc dynamic var stanza_id: String?
#objc dynamic var selected_message_reply_id: String?
#objc dynamic var burn_time: String?
#objc dynamic var schedule_timestamp: String?
#objc dynamic var is_scheduled: Bool = false
#objc dynamic var room_jid: String?
#objc dynamic var sender_jid: String?
#objc dynamic var is_deleted: Bool = false
}
I would like to fetch all conversation with is_archive == false and only those messageslist with is_deleted = false
I am trying to fetch with this code but its only filtering ConversationModel and not applying filter on Message Model
var result = realm.objects(ConversationModel.self).filter("is_archive = \(is_archive)
AND ANY messagesList.is_deleted == \(boolFalse) AND ANY messagesList.sender_timestamp <=
\(timeStamp)").sorted(byKeyPath: "last_timestamp", ascending: false)
I have tried Nested queries but unable to get desired result.
This isn't exactly an answer but more confirmation that your code is correct and working as intended.
To test, I copy and pasted your code and created sample data and added an _id object to ConversationModel so I could tell which was being retrieved by the query.
So we have three conversations, each having a message. The goal is for the query to retrieve conversation c1; its is_archive is false, it has a message where is_deleted is false and a sender_timestamp <= 5
let c0 = ConversationModel()
c0._id = "c0"
c0.is_archive = true
let c1 = ConversationModel()
c1._id = "c1"
c1.is_archive = false
let c2 = ConversationModel()
c2._id = "c2"
c2.is_archive = false
let m0 = MessageModel()
let m1 = MessageModel()
let m2 = MessageModel()
m0.sender_timestamp = 0
m1.sender_timestamp = 1
m2.sender_timestamp = 2
m0.is_deleted = true
m1.is_deleted = false
m2.is_deleted = true
c0.messagesList.append(m0)
c1.messagesList.append(m1)
c2.messagesList.append(m2)
try! realm.write {
realm.add([c0, c1, c2])
}
Then I ran your query, adding vars.
let is_archive = false
let boolFalse = false
let timeStamp = 5
var results = realm.objects(ConversationModel.self).filter("is_archive = \(is_archive) AND ANY messagesList.is_deleted == \(boolFalse) AND ANY messagesList.sender_timestamp <= \(timeStamp)").sorted(byKeyPath: "last_timestamp", ascending: false)
which produced this output
c1
Unfortunately you can't specify MessageMode constraints in your ConversationModel query. What you can do is create a lazy property consisting of MessageModel objects with constraints on the is_deleted and sender_timestamp properties.
class ConversationModel: Object {
// all other properties ...
var messagesList = List<MessageModel>()
lazy var activeMessages: Results<MessageModel> = {
return messagesList
.filter(.notDeleted)
.filter(.sentOnOrBefore(SOME_TIMESTAMP))
}()
override class func ignoredProperties() -> [String] {
return ["activeMessages"]
}
}
Personally, I like to organize my filter constraints like this:
extension NSPredicate {
static let notArchived = NSPredicate(format: "is_archive == false")
static let notDeleted = NSPredicate(format: "is_deleted == false")
static func sentOnOrBefore(_ timestamp: CLong) -> NSPredicate {
return NSPredicate(format: "sender_timestamp <= %d", timestamp)
}
}
extension SortDescriptor {
static let lastTimestampDescending = SortDescriptor(keyPath: "last_timestamp", ascending: false)
}
To fetch the Conversations we can do this:
func fetchConversations() throws -> Results<ConversationModel> {
let realm = try Realm()
return realm.objects(ConversationModel.self)
.filter(.notArchived)
.sorted(by: [.lastTimestampDescending])
}
Then to access the constrained messages on each conversation we can do something like this:
func processMessages(for conversations: Results<ConversationModel>) {
for conversation in conversations {
print(conversation.activeMessages)
}
}

how to implement multiple user on realm database in iOS?

I am a beginner on programming and especially on iOS development
currently I am trying to use realm as the local database in an ecommerce app. I have Product and WishList object of Realm like below
The product:
class Product : Object {
#objc dynamic var productID : Int = 0
#objc dynamic var name : String = ""
#objc dynamic var categoryID : Int = 0
#objc dynamic var categoryName : String = ""
#objc dynamic var unitPrice: Double = 0.0
#objc dynamic var quantityInCart = 0
#objc dynamic var quantityFromServer = 0
#objc dynamic var descriptionProduct : String = ""
#objc dynamic var hasBeenAddedToWishList : Bool = false
#objc dynamic var hasBeenAddedToCart : Bool = false
#objc dynamic var isNewProduct : Bool = false
#objc dynamic var productWeight : String = ""
#objc dynamic var weightUnit : String = ""
#objc dynamic var minimumOrderQuantity = 0
#objc dynamic var maximumOrderQuantity = 0
override static func primaryKey() -> String? {
return "productID"
}
}
the Wishlist:
class WishList : Object {
var products = List<Product>()
}
my app can change the user. so let say if User A put some products on the wishlist (populates the WishList object with the product), after that he performs Log Out,
then it will make the User B's wishlist object will already have object after User B login.
so I think I need to insert userID both on Product and Wishlist object, and I have to also remove the primary key on Product object.
override static func primaryKey() -> String? {
return "productID"
}
so when I perform query or filter from realm database I can filter based on productID and also userID.
do I have the correct approach using way like that ? or is there a better approach? because to I am not comfortable having userID as the property of Product object like code below:
class Product : Object {
#objc dynamic var userID : Int = 0 <--- like this
#objc dynamic var productID : Int = 0
#objc dynamic var name : String = ""
#objc dynamic var categoryID : Int = 0
#objc dynamic var categoryName : String = ""
#objc dynamic var unitPrice: Double = 0.0
#objc dynamic var quantityInCart = 0
#objc dynamic var quantityFromServer = 0
#objc dynamic var descriptionProduct : String = ""
}
class WishList : Object {
#objc dynamic var userID : Int = 0 <--- and like this
var products = List<Product>()
}
and with this approach, I will also have 'duplicate' Product data on Product object with the same productID, but the userID on the property of the Product is different
You shouldn't add userID to either the Product or the Wishlist. A Product should be independent of specific users, so it should have no relationship to a user. On the other hand, a Wishlist is specific to a user, but instead of manually having to query the userID property of a specific Wishlist, you should take advantage of Realm's built-in relationships and declare a one-to-one relationship between a User and a Wishlist (you can either declare the relationship on WishList or on User, both work just fine).
So your Product definition should be left unchanged with its primaryKey being intact as well. Your Wishlist should look like the following:
class WishList : Object {
#objc dynamic var user: User?
let products = List<Product>()
}
Or if you want to access the WishList of a specific User from the user, you can modify your User like so:
class User: Object {
#objc dynamic var wishList: WishList?
...
}

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.

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())
}

Resources