Firestore crashes while trying to create a document - swift

I have a problem with a FireStore, hope some of you could help me.
I'm trying to create a document this way:
class FireStoreUtils: NSObject {
static let defaultUtils = FireStoreUtils()
var db = Firestore.firestore()
var fireStoreSettings = FirestoreSettings.init()
override init() {
super.init()
fireStoreSettings.host = FireStoreParameters.host
fireStoreSettings.isSSLEnabled = FireStoreParameters.sslEnabled
fireStoreSettings.isPersistenceEnabled = FireStoreParameters.persistenceEnabled
fireStoreSettings.cacheSizeBytes = Int64(FireStoreParameters.cacheSizeBytes)
db.settings = fireStoreSettings
}
weak var delegate:FireStoreUtilsDelegate?
func addNewUser(userData userDictionary: [String: Any],userId uId: String) {
do {
let table = self.db.collection("Collection_name")
let documentRef = table.document(uId)
try? documentRef.setData(userDictionary, completion: { (error) in
if (error != nil) {
self.delegate?.didFailToPerformOperation(errorMessage: error?.localizedDescription)
}
else {
self.delegate?.didSucceedToPerformOperation(message: "Success")
}
})
}
catch let error {
self.delegate?.didFailToPerformOperation(errorMessage: error.localizedDescription)
}
}
But from some reason executing setData I get the following crash
assertion failed: 0 == pthread_setspecific(tls->key, (void)value)*
I tried to use FireStore logs but the last log message I got is
2021-01-17 18:55:12.114707+0200 7.3.0 - [Firebase/Firestore][I-FST000001] Creating Firestore stub.
I added Firestore manually and din't use nor Swift PM or Pods, because both of the didn't work with FirebaseAuth in pod file.
It starts to look like everything is dead end.
If somebody knows what's going on or got similar problem, please,help!
Thank you,
Maria.

Related

Not able to get swift data from kotlin repo

I have a kmm project, I am able to get the data from the kotlin version, but for iOS not. I am getting an exception break with code: Thread 4: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
The data from the repo that I am trying to get:
suspend fun getRestaurantsOrders(): CommonFlow<List<Order>> {
val userId = appService.currentUser!!.id
val restaurant = realm.query<Restaurant>("userID = $0", userId).first().find()!!
return withContext(Dispatchers.Default) {
realm.query<Order>("restaurantID = $0 && totalQuantity > 0 SORT(discount DESC)", restaurant._id.toString())
.asFlow().map {
it.list
}.asCommonFlow()
}
}
The way that I am trying to get data from ios:
func getOrdersList()
{
Task{
do{
try await repo.getRestaurantsOrders().watch(block: {orders in
self.restaurantActiveOrdersList = orders as! [Order] //breaks here
})
}catch{
print("error")
}
}
}
Any idea what I am doing wrong?
I am new at swift, thanks in advance!

How to merge two queries using Firestore - Swift

I need to merge two queries with firebase firestore and then order the results using the timestamp field of the documents.
Online I didn't find much information regarding Swift and Firestore.
This is what I did so far:
db.collection("Notes").whereField("fromUid", isEqualTo: currentUserUid as Any).whereField("toUid", isEqualTo: chatUserUid as Any).getDocuments { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
return
}
db.collection("Notes").whereField("fromUid", isEqualTo: self.chatUserUid as Any).whereField("toUid", isEqualTo: self.currentUserUid as Any).getDocuments { (snaphot1, error1) in
if let err = error1{
print(err.localizedDescription)
return
}
}
}
I added the second query inside the first one on completion but now I don't know how to merge them and order them through the field of timestamp.
On this insightful question It is explained that it's recommended to use a Task object but I don't find anything similar with swift.
There are many ways to accomplish this; here's one option.
To provide an answer, we have to make a couple of additions; first, we need somewhere to store the data retrieved from firebase so here's a class to contains some chat information
class ChatClass {
var from = ""
var to = ""
var msg = ""
var timestamp = 0
convenience init(withDoc: DocumentSnapshot) {
self.init()
self.from = withDoc.get("from") as! String
self.to = withDoc.get("to") as! String
self.msg = withDoc.get("msg") as! String
self.timestamp = withDoc.get("timestamp") as! Int
}
}
then we need a class level array to store it so we can use it later - perhaps as a tableView dataSource
class ViewController: NSViewController {
var sortedChatArray = [ChatClass]()
The setup is we have two users, Jay and Cindy and we want to retrieve all of the chats between them and sort by timestamp (just an Int in this case).
Here's the code that reads in all of the chats from one user to another creates ChatClass objects and adds them to an array. When complete that array is passed back to the calling completion handler for further processing.
func chatQuery(from: String, to: String, completion: #escaping( [ChatClass] ) -> Void) {
let chatsColl = self.db.collection("chats") //self.db points to my Firestore
chatsColl.whereField("from", isEqualTo: from).whereField("to", isEqualTo: to).getDocuments(completion: { snapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = snapshot?.documents else { return }
var chatArray = [ChatClass]()
for doc in docs {
let chat = ChatClass(withDoc: doc)
chatArray.append(chat)
}
completion(chatArray)
})
}
Then the tricky bit. The code calls the above code which returns an array The above code is called again, returning another array. The arrays are combined, sorted and printed to console.
func buildChatArray() {
self.chatQuery(from: "Jay", to: "Cindy", completion: { jayCindyArray in
self.chatQuery(from: "Cindy", to: "Jay", completion: { cindyJayArray in
let unsortedArray = jayCindyArray + cindyJayArray
self.sortedChatArray = unsortedArray.sorted(by: { $0.timestamp < $1.timestamp })
for chat in self.sortedChatArray {
print(chat.timestamp, chat.from, chat.to, chat.msg)
}
})
})
}
and the output
ts: 2 from: Cindy to: Jay msg: Hey Jay, Sup.
ts: 3 from: Jay to: Cindy msg: Hi Cindy. Not much
ts: 9 from: Jay to: Cindy msg: Talk to you later

SwiftUI and Firebase - Stream error: 'Not found: No document to update:

So, I have a program that, when it opens, looks for a specific document name in a specific collection (both specified) and, when it is found, copies the document name and starts a listener. If it doesn't find the document name after 5 x 5 second intervals, the app stops. For some reason, when I run the code, after it does the first check I get about a thousand writes of this error:
[Firebase/Firestore][I-FST000001] WriteStream (7ffcbec0eac8) Stream error: 'Not found: No document to update:
Here's the code I'm using to call firestore:
let capturedCode: String? = "party"
.onAppear(perform: {
Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { timer in
print("running code check sequence")
if let code = capturedCode {
calcCloud.checkSessionCode(code)
if env.doesCodeExist {
print("code found! applying to environment!")
env.currentSessionCode = code
calcCloud.watchCloudDataAndUpdate()
allClear(env: env)
timer.invalidate()
}
else if timerCycles < 5 {
timerCycles += 1
print("code not found, this is cycle \(timerCycles) of 5")
} else {
print("could not find document on firebase, now committing suicide")
let x = ""
let _ = Int(x)!
}
}
}
})
here is the code I'm using to check firebase:
func checkSessionCode(_ code: String) {
print("checkSessionCode running")
let docRef = self.env.db.collection(K.sessions).document(code)
docRef.getDocument { (document, error) in
if document!.exists {
print("Document data: \(document!.data())")
self.env.doesCodeExist = true
} else {
print("Document does not exist")
self.env.doesCodeExist = false
}
}
}
and here is the code that should be executed if the code is found and applied:
func watchCloudDataAndUpdate() {
env.db.collection(K.sessions).document(env.currentSessionCode!).addSnapshotListener { (documentSnapshot, error) in
guard let document = documentSnapshot else {
print("Error fetching snapshot: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
Where did I go wrong, and what is this error all about...thanks in advance :)
EDIT: For clarity, it seems that the errors begin once the onAppear finishes executing...
This is why I need to stop coding after 1am...on my simulator, I deleted my app and relaunched and everything started working again...sometimes the simplest answers are the right ones...

I cannot get the AWS Cognito credentials of a user (swiftUI)

I have tried a couple of different things, and at this point I am stumped. I simply want to be able to access the user's email to present it in a view. However I have not been able to successfully present, much less retrieve, this information. Here are the two pieces of code I have tried with:
func getUsername() -> String? {
if(self.isAuth) {
return AWSMobileClient.default().username
} else {
return nil
}
}
and
func getUserEmail() -> String {
var returnValue = String()
AWSMobileClient.default().getUserAttributes { (attributes, error) in
if(error != nil){
print("ERROR: \(String(describing: error))")
}else{
if let attributesDict = attributes{
//print(attributesDict["email"])
self.name = attributesDict["name"]!
returnValue = attributesDict["name"]!
}
}
}
print("return value: \(returnValue)")
return returnValue
}
Does anyone know why this is not working?
After sign in try this:
AWSMobileClient.default().getTokens { (tokens, error) in
if let error = error {
print("error \(error)")
} else if let tokens = tokens {
let claims = tokens.idToken?.claims
print("claims \(claims)")
print("email? \(claims?["email"] as? String ?? "No email")")
}
}
I've tried getting the user attributes using AWSMobileClient getUserAttributes with no success. Also tried using AWSCognitoIdentityPool getDetails With no success. Might be an error from AWS Mobile Client, but we can still get attributes from the id token, as seen above.
If you are using Hosted UI, remember to give your hosted UI the correct scopes, for example:
let hostedUIOptions = HostedUIOptions(scopes: ["openid", "email", "profile"], identityProvider: "Google")
It is because it is an async function so will return but later than when the function actually ends with the value. Only way I found to do it is placing a while loop and then using an if condition.

How to get an array of CNGroup from a CNContainer using CNContactStore?

I'm looking for a way to get a list of groups (CNGroup) that relate to a contact container (CNContainer). When I use a predicate it fails.
The code I'm using is
func populateGroups(tableView:NSTableView,container:CNContainer){
print("populateGroups.start")
print(container.name)
print(container.identifier)
let contactStore = CNContactStore()
do {
let groupsPredicate = CNGroup.predicateForGroups(withIdentifiers: [container.identifier])
groups = try contactStore.groups(matching: groupsPredicate)
groupNames.removeAll();
for group:CNGroup in groups {
self.groupNames.append(group.name)
}
tableView.reloadData()
} catch {
print( "Unexpected error fetching groups")
}
print("populateGroups.finish")
}
I'm getting an error from that doesn't make sense to me.
The line groups = try contactStore.groups(matching: groupsPredicate) causes an error.
[Accounts] Failed to update account with identifier 47008233-A663-4A52-8487-9D7505847E29, error: Error Domain=ABAddressBookErrorDomain Code=1002 "(null)"
Which is confusing as I'm not updating any account.
If I change that line of code to groups = try contactStore.groups(matching: nil)
I get all the groups for all the containers.
How do you create a predicate that will return all the CNGroups that belong to a CNContactContainer?
I worked around this by checking that each group from all the groups belonged to the container in question using CNContainer.predicateForContainerOfGroup
func populateGroups(tableView:NSTableView,container:CNContainer){
let contactStore = CNContactStore()
do {
let groups:[CNGroup] = try contactStore.groups(matching: nil)
self.groups.removeAll();
groupNames.removeAll();
for group:CNGroup in groups {
let groupContainerPredicate:NSPredicate = CNContainer.predicateForContainerOfGroup(withIdentifier: group.identifier)
let groupContainer:[CNContainer] = try contactStore.containers(matching: groupContainerPredicate)
if( groupContainer[0].identifier == container.identifier) {
self.groupNames.append(group.name)
self.groups.append(group)
}
}
tableView.reloadData()
} catch {
print( "Unexpected error fetching groups")
}
}