create Realm DB for each user in Chat App - swift

this one for sending message and save it to realm db
var messageIndex = try! Realm().objects(MessageRealm.self).sorted(byKeyPath: "timeStamp")
func didPressSend(text: String) {
if self.inputContinerView.inputTextField.text! != "" {
let messageDB = MessageRealm()
let realm = try! Realm()
let userRealm = UsersRealm()
messageDB.textDownloadded = text
messageDB.fromId = user!.fromId
messageDB.timeStamp = Date()
print(messageDB)
try! realm.write ({
print(realm.configuration.fileURL)
userRealm.msgs.append(messageDB)
//realm.create(MessageRealm.self, value: ["textDownloadded": text, "fromId": user!.fromId, "timeStamp": Date()])
})
if let userTitleName = user?.toId {
print(userTitleName)
OneMessage.sendMessage(text, thread: "AAAWatree", to: userTitleName, isPhoto: false, isVideo: false, isVoice: false, isLocation: false, timeStamp: date, completionHandler: { (stream, message) in
DispatchQueue.main.async {
OneMessage.sharedInstance.deleteCoreDataMessage()
}
self.inputContinerView.inputTextField.text! = ""
})
}
}
}
This for when recieving message im trying to save user (send id )
let realm = try! Realm()
userData.sender = sender
userData.toId = toUser
print(userData.sender)
print(userData.toId)
try! realm.write ({
realm.add(userData, update: true)
})
this my Realm Object Class
class MessageRealm: Object {
dynamic var textDownloadded = String()
dynamic var imageDownloadded = NSData()
dynamic var videoDownloadded = String()
dynamic var voiceDownloadded = String()
dynamic var fromId = String()
dynamic var timeStamp = Date()
dynamic var messageId = NSUUID().uuidString
let userSelect = List<UsersRealm>()
override class func primaryKey() -> String? {
return "messageId"
}
}
class UsersRealm: Object {
dynamic var sender = String()
dynamic var fromId = String()
dynamic var toId = String()
dynamic var lastMessage = String()
dynamic var timeStamp = Date()
dynamic var profileImage = NSData()
let msgs = List<MessageRealm>()
override class func primaryKey() -> String {
return "sender"
}
}
sending and reciving is ok and its save to realm db but all any user send message i recived in one user i want to seprate for every user have his sending and recive database i miss something here but i dont know i try to search nothing its long question but i cant figure out the soluation
and sorry for my week english
Thank you

If I understood your case correctly you're using a single realm url for all users that's why all your clients have the same data. You should probably create a separate realm for the conversation and share it between the users who participate in that chat. Please learn more about sharing realms in our docs at https://realm.io/docs/swift/latest/#access-control.

Related

Swift: Thread 1: signal SIGABRT- Getting and displaying data from Firestore

I'm a beginner trying to get the app to be able to post and see posts that are in Firebase. Every time I run this part of the app I get an error and the app crashes. Any help?
The error occurs on this line: let time = doc.document.data()["time"] as! Timestamp
(Thread 1: signal SIGABRT)
This is part of my code,
import SwiftUI
import Firebase
class PostViewModel : ObservableObject{
#Published var posts : [PostModel] = []
#Published var noPosts = false
#Published var newPost = false
#Published var updateId = ""
init() {
getAllPosts()
}
func getAllPosts(){
ref.collection("Posts").addSnapshotListener { (snap, err) in
guard let docs = snap else{
self.noPosts = true
return
}
if docs.documentChanges.isEmpty{
self.noPosts = true
return
}
docs.documentChanges.forEach { (doc) in
// Checking If Doc Added...
if doc.type == .added{
// Retrieving and appending...
let title = doc.document.data()["title"] as! String
let time = doc.document.data()["time"] as! Timestamp
let pic = doc.document.data()["url"] as! String
let userRef = doc.document.data()["ref"] as! DocumentReference

Struggling to pass data to UI - Swift

Good day, I'm trying to pass data to my Profile UI View.
This is my Customer Class:
class Customer {
// Creating a customer
let name: String
let surname: String
let contactNo: String
let email: String
init(name: String,surname: String,contactNo: String,email: String) {
self.name = name
self.surname = surname
self.contactNo = contactNo
self.email = email
}
}
This is my code whereby I try to parse data from Firestore to display a customers details:
class ProfileCus: UIViewController {
// Labels to display data
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var surnameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var contactLabel: UILabel!
// Reference to customer collection in Firestore
private var customerRefCollection: CollectionReference!
// Customer Object
private var customer: Customer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
customerRefCollection = Firestore.firestore().collection("customers")
nameLabel.text = customer?.name
surnameLabel.text = customer?.surname
emailLabel.text = customer?.email
contactLabel.text = customer?.contactNo
}
// This function notifies the view controller that the view is about to load so it is best to acquire the data in here before the view loads so that it will be ready to display.
override func viewWillAppear(_ animated: Bool) {
// Get the current user ID
let userID = Auth.auth().currentUser?.uid
// Locate the user information on Firestore
customerRefCollection.document(userID!).getDocument { (snapshot, error) in
if let err = error {
debugPrint("Error fetching documents: \(err)")
}
else {
// Ensure that if there's nothing in the document that the function returns
guard let snap = snapshot else {return}
// Parse the data to the customer model
let data = snap.data()
let name = data?["name"] as? String ?? ""
let surname = data?["surname"] as? String ?? ""
let email = data?["email"] as? String ?? ""
let contact = data?["contact no"] as? String ?? ""
// Create the customer and pass it to the global variable
let cus = Customer(name: name, surname: surname, contactNo: contact, email: email)
self.customer = cus
}
}
}
}
Everything on the Firestore side is working fine and I am able to read/retrieve data but I'm struggling to pass the data to my UI via my Customer Class. Using print statements it seems as if the customer object is nil.
Output once the code runs
func getDataFromFirebase(completion:#escaping() -> ()){
let userID = Auth.auth().currentUser?.uid
// Locate the user information on Firestore
customerRefCollection.document(userID!).getDocument { (snapshot, error) in
if let err = error {
debugPrint("Error fetching documents: \(err)")
}
else {
// Ensure that if there's nothing in the document that the function returns
guard let snap = snapshot else {return}
// Parse the data to the customer model
let data = snap.data()
let name = data?["name"] as? String ?? ""
let surname = data?["surname"] as? String ?? ""
let email = data?["email"] as? String ?? ""
let contact = data?["contact no"] as? String ?? ""
// Create the customer and pass it to the global variable
let cus = Customer(name: name, surname: surname, contactNo: contact, email: email)
self.customer = cus
}
completion()
}
}
getDataFromFirebase{
customerRefCollection = Firestore.firestore().collection("customers")
nameLabel.text = customer?.name
surnameLabel.text = customer?.surname
emailLabel.text = customer?.email
contactLabel.text = customer?.contactNo
}
So what you're basically doing here is you're first getting the data from the firebase and only after this work is done, hence the completion block you will be setting your data to the view. You can call the method simply in viewDidLoad.

Realm objects returns nil after adding

I created an Person object when the User logs in:
let creds = SyncCredentials.jwt(accessToken)
SyncUser.logIn(with: creds, server: Constants.syncAuthURL, onCompletion: { [weak self](user, err) in
if let user = user {
self?.setDefaultRealmConfiguration(with: user)
let realm = try! Realm()
let identity = (user.identity)!
let person = Person()
person.id = identity
try! realm.write {
realm.add(person, update: true)
}
self?.performSegue(withIdentifier: "showProfile", sender: self)
}
})
The Person successfully created on the cloud server.
In the next viewcontroller i like to fetch the object based on the id:
let realm = try! Realm()
guard let uuid = SyncUser.current?.identity! else { return }
let person = realm.objects(Person.self).filter("id = %#", uuid).first
try! realm.write {
person?.name = "test"
}
The person is always nil I also tried the query the object with the primary key, but with no success.
The Person class looks like:
class Person : Object {
#objc dynamic var id = ""
#objc dynamic var created: Date = Date()
#objc dynamic var name = ""
#objc dynamic var email = ""
#objc dynamic var avatar : Data?
override static func primaryKey() -> String? {
return "id"
}
}
UPDATE
I created a new app with just one Viewcontroller and the Person class:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let creds = SyncCredentials.usernamePassword(username: "admin", password: "test")
SyncUser.logIn(with: creds, server: Constants.AUTH_URL, onCompletion: { (user, err) in
if let user = user {
var config = user.configuration(realmURL: Constants.REALM_URL)
config.objectTypes = [Person.self]
Realm.asyncOpen(configuration: config, callback: { (realm, error) in
guard let realm = realm else {return}
let objects = realm.objects(Person.self)
print(objects) // always empty why???
try! realm.write {
let p = Person()
p.id = "test"
realm.add(p)
}
print(objects) // one object
})
}
})
}
}
as with my other problem the person is successfully added to the cloud. but when I restart the app the objects are empty on the first query. Maybe I miss understanding something with the synched realms?
let results = realm.objects(Person.self)
let subscription = results.subscribe()
print(results)
resolve my problem

query Object from Realm List

enter image description herei'm trying to query object from realm
class MessageRealm: Object {
dynamic var fromId = String()
dynamic var messageID = String()
dynamic var textDownloadded = String()
override class func primaryKey() -> String? {
return "messageID"
}
}
class UsersRealm: Object {
dynamic var sender = String()
let msgs = List<MessageRealm>()
override class func primaryKey() -> String? {
return "sender"
}
}
i have two class one for messages and the other for users, every users have a list of messages and i need to query thats message based on (UserRealm.sender)
This is the realm DB
I solve the issue by this way if anyone face the same
var messageIndex: Results<MessageRealm>!
let realm = try! Realm()
let mssagesRealm = realm.objects(UsersRealm.self).filter("sender = %#", userTitleName)
for sub in mssagesRealm {
messageIndex = sub.msgs.sorted(byKeyPath: "timeStamp")
}

Using Realm with MPMediaQuery

I want to build an Audiobookplayer which can set Bookmarks. Loading the Audiobooks from my Library with MPMediaQuery works fine, but when I take an audiobook off through iTunes, it stays in my realmfile.
I would like realm to delete the entry automatically when the playlist is updated through iTunes, but I can't seem to figure out how.
Here is my code.
class Books: Object {
dynamic var artistName: String?
dynamic var albumTitle: String?
dynamic var artwork: NSData?
dynamic var albumUrl: String?
dynamic var persistentID: String?
let parts = List<BookParts>()
override static func primaryKey() -> String? {
return "persistentID"
}
override class func indexedProperties() -> [String] {
return ["albumTitle"]
}
convenience init(artistName: String, albumTitle: String, albumUrl: String) {
self.init()
self.artistName = artistName
self.albumTitle = albumTitle
self.albumUrl = albumUrl
}
class BookQuery {
let realm = try! Realm()
var bookItems = Array<Books>()
var partItems = Array<BookParts>()
func getBooks() {
let query: MPMediaQuery = MPMediaQuery.audiobooks()
query.groupingType = .album
let collection: [MPMediaItemCollection] = query.collections!
try! realm.write {
for allbooks in collection {
let item = allbooks.representativeItem
let book = Books()
let id = item?.value(forProperty: MPMediaItemPropertyAlbumPersistentID) as! Int
book.artistName = item?.artist
book.albumTitle = item?.albumTitle
book.albumUrl = item?.assetURL?.absoluteString
book.artwork = Helper.getArtwork(item?.artwork) as NSData?
book.persistentID = id.stringValue
realm.add(book, update: true)
guard realm.object(ofType: Books.self, forPrimaryKey: "persistentID") != nil else {
continue
}
bookItems.append(book)
}
}
}
}
I calling the MediaQuery in "viewDidLoad" in my LibraryViewController.
I am pretty new to coding and are trying to solve this for a while.
Thanks for any help.
The high level thing you'll need to do is to have a way to detect when the iTunes playlist is updated and then delete the removed items' corresponding objects from the Realm.
A general approach to this is to get all the "persistent ID"s currently in the Realm at the start of the for loop, put those in an array, remove each ID it sees from the array, then delete objects with the persistent ID in the array that's left, since those weren't in the collection.