how to big api response insert in Realm DB insert in background thread and update table view ui? - realm

class func insertProductCombinationInDd(objects: [[String: Any]]) {
var objs = [[String: Any]]()
for var object in objects {
let attributs = object["attributes"] as? [[String: Any]]
let strAttribute = OAxeBaseViewController.jsonString(from: attributs ?? [:])
object["attributes"] = strAttribute
objs.append(object)
}
if !objs.isEmpty {
do {
let realm = try Realm()
try realm.write {
for combi in objs {
let combination = ProductCombination()
combination.id = combi["id"] as? String ?? ""
combination.productId = combi["product_id"] as? String ?? ""
combination.orgId = combi["org_id"] as? String ?? ""
combination.attributes = combi["attributes"] as? String ?? ""
combination.mrp = combi["mrp"] as? Double ?? 0.0
combination.quantity = combi["quantity"] as? Int ?? 0
combination.updatedAt = combi["updation_time"] as? Int ?? 0
combination.active = combi["active"] as? Bool ?? false
combination.categoryId = combi["category_id"] as? String ?? ""
realm.add(combination, update: .modified)
}
}
} catch {}
}
}
I written code like this
any other good approach data insert in background thread and update ui similar.
how to update ui immediately when insert or update realm objec?

Related

How to write an Enum in Firestore written in SwiftUI?

I've made a little app where I have categories, and in each categories I have different products, that works well with barcoded data, but now I want to write them in Firestore and fetch them in my application.
I have 2 Struct, one for the products :
struct Product : Identifiable, Hashable {
var id = UUID().uuidString
var type : ProductType
var title : String
var subtitle : String
var description : String = ""
var price : String
var productImage : String = ""
var quantity : Int = 1
}
and one for the category type
enum ProductType : String, CaseIterable {
case Wearable = "Wearable"
case Laptops = "Laptops"
case Phones = "Phones"
case Tablets = "Tablets"
}
This is how I wrote the Product in Firestore : Picture 1, but I do not know how to write the enum.
Also, this is how I'm getting the data from the firestore, but I have an error at:
return Product(id: d.documentID, type: d["type"] as? String ?? ""
Cannot convert value of type 'String' to expected argument type 'ProductType'
func getData() {
FirebaseManager.shared.firestore.collection("products").getDocuments { snapshot, error in
if error == nil {
if let snapshot = snapshot {
DispatchQueue.main.async {
self.products = snapshot.documents.map { d in
return Product(id: d.documentID, type: d["type"] as? String ?? ""
, title: d["title"] as? String ?? "",
subtitle: d["subtitle"] as? String ?? "",
price: d["price"] as? String ?? "", productImage: d["productImage"] as? String ?? ""
)
}
}
}
}
else {
}
}
}
This is for "Lore Ipsum comment "
func getData() {
FirebaseManager.shared.firestore.collection("products").getDocuments { snapshot, error in
if error == nil {
if let snapshot = snapshot {
DispatchQueue.main.async {
self.products = snapshot.documents.compactMap { document in
try? document.data(as: Product.self)
} ?? []
}
}
}
else {
}
}
}
Also, this is my FirebaseManager :
class FirebaseManager : NSObject {
let auth : Auth
let storage : Storage
let firestore : Firestore
static let shared = FirebaseManager()
override init() {
self.auth = Auth.auth()
self.storage = Storage.storage()
self.firestore = Firestore.firestore()
}
}
Question, how can I write that enum into firestore?
I think it could work like this
Even if the code readability is reduced
type: ProductType(rawValue: d["type"] as? String ?? "") ?? .Wearable // default value for ProductType

Reference to member 'decor' cannot be resolved without a contextual type

I have been following the tutorial on youtube by Reality School. This part is for the firebase store model for storing usdz models with thumbnails. I have got stuck at .decor it is saying " Reference to member 'decor' cannot be resolved without a contextual type"
I do not have any reference to .decor in any other part of the code. And I can't find anything about it. Can anyone give some pointers in the correct direction?
import Foundation
import FirebaseFirestore
class ModelsViewModel: ObservableObject {
#Published var models: [Model] = []
private let db = Firestore.firestore()
func fetchData() {
db.collection("models").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("Firestore: No documents")
return
}
self.models = documents.map { (queryDocumentSnapshot) -> Model in
let data = queryDocumentSnapshot.data()
let name = data["name"] as? String ?? ""
let categoryText = data["category"] as? String ?? ""
let category = ModelCategory(rawValue: categoryText) ?? .decor
let scaleCompensation = data["scaleCompensation"] as? Double ?? 1.0
return Model(name: name, category: category, scaleCompensation: Float(scaleCompensation))
}
}
}
}
Here is also the model code.
import SwiftUI
import RealityKit
import Combine
enum ModelCategory: String, CaseIterable {
case porches
case gazebos
case pergolas
case garages
case roomabove
case loftedroomabove
var lable: String {
get {
switch self {
case .porches:
return "Porches"
case .gazebos:
return "Gazebos"
case . pergolas:
return "Pergolas"
case .garages:
return "Garages"
case .roomabove:
return "Room Above"
case .loftedroomabove:
return "Lofted Room Above"
}
}
}
}
class Model: ObservableObject, Identifiable {
var id: String = UUID().uuidString
var name: String
var category: ModelCategory
#Published var thumbnail: UIImage
var modelEntity: ModelEntity?
var scaleCompensation: Float
private var cancellable: AnyCancellable?
init(name: String, category: ModelCategory, scaleCompensation: Float = 1.0) {
self.name = name
self.category = category
self.thumbnail = UIImage(systemName: "photo")!
self.scaleCompensation = scaleCompensation
FirebaseStorageHelper.asyncDownloadToFilesystem(relativePath: "thumbnails/\(self.name).png") { localUrl in
do {
let imageData = try Data(contentsOf: localUrl)
self.thumbnail = UIImage(data: imageData) ?? self.thumbnail
} catch {
print("Error loading image: \(error.localizedDescription)")
}
}
}
//async model loading
func asyncLoadModelEntity() {
let filename = self.name + ".usdz"
self.cancellable = ModelEntity.loadModelAsync(named: filename)
.sink(receiveCompletion: { loadCompletion in
switch loadCompletion {
case .failure(let error): print("Unable to load modelEntity for \(filename) Error: \(error.localizedDescription)")
case .finished:
break
}
}, receiveValue: { modelEntity in
self.modelEntity = modelEntity
self.modelEntity?.scale *= self.scaleCompensation
print("modelEntity for \(self.name) has been loaded")
})
}
}

Is there a way to give initial value in an instance in property initializer dynamically using SwiftUI and Firebase?

Hi I am currently making a dating app's chat page that you can have different rooms for every match using SwiftUI and Cloud Firestore.
I would like to show different chat room every time you tap different user on the top page depending on the matchId.
For now, I need to type the right one in the View file in order to make it work correctly, however, Id like to assign it dynamically.
How can I add the correct matchId to the instance in the View file? Or, should I try different ways?
First, this is the top page.
VStack{
Text("Match Users")
List(self.shareData.matchUserArray){ user in
NavigationLink(destination: MessageView(matchUserInfo: user)){
HStack{
Text(user.name)
Text(user.age)
}
}
}
}
And this is the View file. Without typing "Ll73RINefGxEcYQJoWSE" in the MessageViewModel instance and instead giving it "", I can see the messages in the debug area but don't see any in List.
struct MessageView: View {
var matchUserInfo: User
#ObservedObject var msgVM = MessageViewModel(matchId: "Ll73RINefGxEcYQJoWSE")
#EnvironmentObject var shareData : ShareData
#State var text = ""
#State var matchId = ""
var body: some View {
VStack{
List(self.msgVM.messages, id: \.id){ i in
if i.fromUser == self.shareData.currentUserData["id"] as? String ?? ""
{
MessageRow(message: i.msg, isMyMessage: true)
} else if i.toUser == self.shareData.currentUserData["id"] as? String ?? ""
{
MessageRow(message: i.msg, isMyMessage: false)
}
}
.onAppear { UITableView.appearance().separatorStyle = .none }
.onDisappear { UITableView.appearance().separatorStyle = .singleLine }
HStack{
TextField("message here", text: $text).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
Button(action: {
if self.text.count > 0 {
self.msgVM.sendMsg(msg: self.text, toUser: self.matchUserInfo.id, fromUser: self.shareData.currentUserData["id"] as! String, matchId: self.msgVM.matchId)
self.text = ""
}
}) {
Image(systemName: "paperplane")
}.padding(.trailing)
}
}
.navigationBarTitle("\(self.matchUserInfo.name)", displayMode: .inline)
.onAppear{
DispatchQueue.global().async{
self.getMatchId(partner: self.matchUserInfo)
}
_ = MessageViewModel(matchId: self.matchId)
}
.onDisappear{
print(self.msgVM.messages)
}
}
func getMatchId(partner: User){
Firestore.firestore().collection("MatchTable").document(self.shareData.currentUserData["id"] as? String ?? "").collection("MatchUser").whereField("MatchUserId", isEqualTo: partner.id).getDocuments { (snap, err) in
if let snap = snap {
for id in snap.documents{
self.msgVM.matchId = id.data()["MatchRoomId"] as? String ?? ""
_ = MessageViewModel(matchId: self.msgVM.matchId)
self.matchId = self.msgVM.matchId
}
}
}
}
}
Also this is the firebase part.
import Foundation
import FirebaseFirestore
struct Message: Identifiable {
var id: String
var msg: String
var fromUser: String
var toUser: String
var date: Timestamp
var matchId : String
}
class MessageViewModel: ObservableObject {
var datas = FirebaseData()
let db = Firestore.firestore()
#Published var matchId:String
#Published var messages = [Message]()
init(matchId: String){
self.matchId = matchId
self.db.collection("Messages").whereField("matchId", isEqualTo: self.matchId).order(by: "date").addSnapshotListener { (snap, error) in
if let error = error {
print(error.localizedDescription)
return
}
if let snap = snap {
for i in snap.documentChanges {
if i.type == .added{
let toUser = i.document.get("toUser") as! String
let fromUser = i.document.get("fromUser") as! String
let message = i.document.get("message") as! String
let id = i.document.documentID
let date = i.document.get("date") as! Timestamp
let matchId = i.document.get("matchId") as! String
self.messages.append(Message(id: id, msg: message, fromUser: fromUser, toUser: toUser, date: date, matchId: matchId))
}
}
}
}
}
func sendMsg(msg: String, toUser: String, fromUser: String, matchId: String){
let data = [
"message": msg,
"toUser": toUser,
"fromUser": fromUser,
"date": Timestamp(),
"matchId": matchId
] as [String : Any]
Firestore.firestore().collection("Messages").addDocument(data: data){ error in
if let err = error {
print(err.localizedDescription)
return
}
print("Sent message")
}
}
}
Thank you
All you should really need is to construct your ObservedObject in an init function:
let matchUserInfo: User
#ObservedObject private var msgVM: MessageViewModel
init(_ user: User) {
self.matchUserInfo = user
self._msgVM = ObservedObject(initialValue: MessageViewModel(matchId: user.matchId))
}
Assuming, of course, that the matchId you care about is passed in via your User type. You know your data structures better than I do, the key here is to simply create your observed object based on your passed in User.

query ordering data firebase swift 5 not working

I am having a problem with sorting data from firebase. The result of my code is completely unordered. I want to order it by the "date".
I have already tried with .queryOrderedBy(child: "date"), but I got the same issue.
Can someone helps me?
func getPosts(){
let ref = Database.database().reference()
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
let postsSnap = snap.value as! [String : AnyObject]
for (_,post) in postsSnap {
let posst = Post()
if let author = post["author"] as? String, late date = post["date"], let postID = post["postID"] as? String, let userID = post["userID"] as? String {
posst.date = date
posst.author = author
posst.postID = postID
posst.userID = userID
self.posts.append(posst)
}
self.collectionview.reloadData()
}
})
}
My Firebase-Database structure looks like this:
{
"posts" : {
"Optional(\"-M2tKGSlfsUng8XfmnbV\")" : {
"author" : "Lilli",
"postID" : "-M2tKGSlfsUng8XfmnbV",
"date" : 1584731069721,
"userID" : "cayQLr27tsaJR76nH4H6yVUAOP03"
},
}
},
Just use following code
self.posts.sort(by: {$0.date > $1.date})

Converting DataSnapshot to custom struct object - Swift 4

So, In my project I've created a custom struct:
import Foundation
import Firebase
struct CheckedIn {
let ref: DatabaseReference?
let key: String
let max_cm: String
let max_in: String
let weight_kg: Int
let weight_lb: Int
init(key: String = "", max_cm: String, max_in: String, weight_kg: Int, weight_lb: Int) {
self.ref = nil
self.key = key
self.max_cm = max_cm
self.max_in = max_in
self.weight_kg = weight_kg
self.weight_lb = weight_lb
}
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: AnyObject],
let max_cm = value["checked_max_cm"] as? String,
let max_in = value["checked_max_in"] as? String,
let weight_kg = value["checked_weight_kg"] as? Int,
let weight_lb = value["checked_weight_in"] as? Int
else {
return nil
}
self.ref = snapshot.ref as DatabaseReference
self.key = snapshot.key
self.max_cm = max_cm
self.max_in = max_in
self.weight_kg = weight_kg
self.weight_lb = weight_lb
}
func toAnyObject() -> Any {
return [
"checked_max_cm": self.max_cm,
"checked_max_in": self.max_in,
"checked_weight_kg": self.weight_kg,
"checked_weight_in": self.weight_lb
]
}
}
This is the structure of my database:
And I'm trying to retrieve some data in a view controller using the following code:
ref.queryOrderedByKey().observe(.value) { (snapshot) in
var newItems: [CheckedIn] = []
for child in snapshot.children {
print(child)
if let snapshot = child as? DataSnapshot, let company = CheckedIn(snapshot: snapshot) {
newItems.append(company)
}
}
print(newItems)
self.companiesCheckedIn = newItems
self.tableView.reloadData()
UIViewController.removeSpinner(spinner: sv)
}
The problem is that, whenever I try to open the view controller (this chunk of code is inside the .viewDidLoad), the list 'newItems' is empty. The strange thing is that when I try to run
print(child)
all of the data is printed,
So I assume that the 'if let snapshot = child as? DataSnapshot, let company = CarryOn(snapshot: snapshot)' block is not running, what should I do?
Managed to solve the problem using a workaround:
This code goes before the viewDidLoad() method of your ViewController
let ref = Database.database().reference().child("alldata")
var companyName: [String] = []
var maxCm: [String] = []
var maxIn: [String] = []
var weightKg: [Int] = []
var weightLb: [Int] = []
And in the viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
ref.queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
let snapshotValue = snapshot.value as! [String:[String:AnyObject]]
let sorted = snapshotValue.sorted() { $0.key.lowercased() < $1.key.lowercased() }
for (key, _) in sorted {
let keys = snapshotValue[key]
let company_name = key
self.companyName.append(company_name)
let carry_max_cm = keys?["keyname"] as! String
self.maxCm.append(carry_max_cm)
let carry_max_in = keys?["keyname"] as! String
self.maxIn.append(carry_max_in)
let carry_weight_kg = keys?["keyname"] as! Int
self.weightKg.append(carry_weight_kg)
let carry_weight_lb = keys?["keyname"] as! Int
self.weightLb.append(carry_weight_lb)
}
self.tableView.reloadData()
}
}
let sorted = snapshotValue.sorted() { $0.key.lowercased() < $1.key.lowercased() }
Orders the dictionary alphabetically
your "checked_weight_kg" & "checked_weight_in" is a integer type but you assign String type.
your code ->
let weight_kg = value["checked_weight_kg"] as? String,
let weight_lb = value["checked_weight_in"] as? String
to Change ->
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: AnyObject],
let max_cm = value["carry_max_cm"] as? String,
let max_in = value["carry_max_in"] as? String,
let weight_kg = value["checked_weight_kg"] as? Int,
let weight_lb = value["checked_weight_in"] as? Int
else {
return nil
}
self.ref = snapshot.ref as DatabaseReference
self.key = snapshot.key
self.max_cm = max_cm
self.max_in = max_in
self.weight_kg = weight_kg
self.weight_lb = weight_lb
}

Resources