loop in a loop not working - ios

I'm working on an app for school project.
After accessing the user's contacts, I want to loop through and show only the contacts who are also users of the app. *Their username is their mobile number.
below are 3 functions.
the first one getAppUsers() works fine.
the third one getDisplayedUser() does not work. and i wonder why
the second one getUserContacts() works. but it is only there to check which part of my loop isn't working. :/
so apparently my loop in a loop has something wrong which i can't figure out (it didn't even get to the "you're HERE"). please help me out. THANKS!
var appUsers = [String]()
var contactStore = CNContactStore()
var userContacts = [CNContact]()
var displayedContacts = [name: phoneNumber]()
func getAppUsers() {
let appUsersQuery = PFUser.query()
appUsersQuery?.findObjectsInBackground { (objects, error) in
if error != nil {
print("WTF")
} else if let users = objects {
for object in users {
print("FYEAH!")
if let user = object as? PFUser {
self.appUsers.append(user.username!)
print(user.username)
}
}
}
}
}
func getUserContacts() {
for b in userContacts {
let c = (b.phoneNumbers[0].value).stringValue
let d = c.replacingOccurrences(of: "\\D", with: "", options: .regularExpression, range: c.startIndex..<c.endIndex)
print("you got here")
print(d)
}
}
func getDisplayedUser() {
for a in appUsers {
for b in userContacts {
let c = (b.phoneNumbers[0].value).stringValue
let d = c.replacingOccurrences(of: "\\D", with: "", options: .regularExpression, range: c.startIndex..<c.endIndex)
print("you're HERE")
print(d)
if a == d {
print("FOUND IT")
print(b.givenName + " " + b.familyName)
}
}
}
}

The getDisplayedUser should be call after the loop finished in in getAppUsers because it is executing in asynchronous mode. I added the row after finished loop below
func getAppUsers() {
let appUsersQuery = PFUser.query()
appUsersQuery?.findObjectsInBackground { (objects, error) in
if error != nil {
print("WTF")
} else if let users = objects {
for object in users {
print("FYEAH!")
if let user = object as? PFUser {
self.appUsers.append(user.username!)
print(user.username)
}
}
// Call it here please ..
self.getDisplayedUser()
}
}
}

Related

Can't pass variable value from firebase firestore to another class SWIFT

So I have this function in class Functions :
struct Prices {
var standardPrice: Int!
}
// FUNC PRICING
class Functions {
private var PricingRef: CollectionReference!
var price = Prices()
func getPrice() -> Prices {
PricingRef = Firestore.firestore().collection("ProductXYZ")
PricingRef.getDocuments { (snapshot, error) in
if let err = error {
debugPrint("Error fetching data \(err)")
}
else {
guard let snap = snapshot else { return }
for document in snap.documents {
let data = document.data()
let std = data["standard"] as! String
self.price.standardPrice = Int(std)!
print(self.price.standardPrice!) // This print the intended result
}
}
}
return price
}
}
Then I want to pass the standardPrice value to this class, called PriceList :
class PriceList: UITableViewController {
var price = Prices()
var newStandardPrice = 0
func Price() {
price = Functions().getPrice()
newStandardPrice = price.standardPrice // always error with value nil
}
I always have that error where newStandardPrice is nil.
but the print(self.price.standardPrice!) shows number of result I want.
So as far as I know, the problem here is because it takes time for the firebase firestore to get the data from database.
How do I get the value of standardPrice after its assigned with the new price from firebase database?
Any help will be appreciated
Thankyou
you need to use completion handler because its async function
func getPrice(completion:#escaping (Prices?,Error?)-> Void) {
PricingRef = Firestore.firestore().collection("ProductXYZ")
PricingRef.getDocuments { (snapshot, error) in
if let err = error {
debugPrint("Error fetching data \(err)")
completion(nil,err)
}
else {
guard let snap = snapshot else { return }
for document in snap.documents {
let data = document.data()
let std = data["standard"] as! String
self.price.standardPrice = Int(std)!
print(self.price.standardPrice!) // This print the intended result
completion(self.price.standardPrice,nil)
}
}
}
}
How to use
Functions().getPrice { (price, error) in
if let err = error {
// do something if you get error
} else if let getPrice = price {
// use price
self.price = getPriice
}

altering a variable outside a closure

I am currently encountering a problem. I have a function with an array which has items needing appending to. The items are appended in a closure inside the function and I can see the items in the array only inside the closure. Since the function has a return I need the appended items to be viewed by the function as a whole and not just the array. What can I do to solve this?
var trueOrFalse: Bool = false
var tempArray:[String] = []
let reference_message = reference(.Append).whereField("delay", isEqualTo: 0)
reference_message.getDocuments { (snapshot, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let snapshot = snapshot else { return }
let documents = snapshot.documents
if documents != nil {
for document in documents {
let messageID = document[kMESSAGEID] as? String
tempArray.append(messageID!)
//print(trueOrFalse)
}
}
if trueOrFalse {
if opened && trueOrFalse {
print("Successful Walloping")
}
} else if !trueOrFalse {
if !opened || !trueOrFalse {
decryptedText = placeholderText
}
}
return JSQMessage(senderId: userId, senderDisplayName: name, date: date, text: decryptedText)

QueryEndingAtValue function does not work correctly in Swift firebase

I have been implementing code that is to enable paging scroll to fetch data by a certain amount of data from firebase database.
Firstly, then error says
Terminating app due to uncaught exception 'InvalidQueryParameter',
reason: 'Can't use queryEndingAtValue: with other types than string in
combination with queryOrderedByKey'
The below here is the actual code that produced the above error
static func fetchPostsWith(last_key: String?, completion: #escaping (([PostModel]?) -> Void)) {
var posts = [PostModel]()
let count = 2
let ref = Database.database().reference().child(PATH.all_posts)
let this_key = UInt(count + 1)
let that_key = UInt(count)
let this = ref.queryOrderedByKey().queryEnding(atValue: last_key).queryLimited(toLast: this_key)
let that = ref.queryOrderedByKey().queryLimited(toLast: that_key)
let query = (last_key != nil) ? this : that
query.observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
for snap in snapshot.children {
if let d = snap as? DataSnapshot {
let post = PostModel(snapshot: d)
print(post.key ?? "")
posts.append(post)
}
}
posts.sort { $0.date! > $1.date! }
posts = Array(posts.dropFirst())
completion(posts)
} else {
completion(nil)
}
}
}
What it tries to do is to fetch a path where all posts are stored by auto id. But the error keeps coming out so I do not know what is wrong. Do you have any idea?
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// index is the last and last fetched then
print(self.feeds.count - 1 == indexPath.row, "index ", self.hasFetchedLastPage, "has fetched last")
if self.feeds.count - 1 == indexPath.row {
let lastKey = self.feeds[indexPath.row].key
if lastKey != self.previousKey {
self.getFeeds(lastKey: lastKey)
} else {
self.previousKey = lastKey ?? ""
}
}
print("Cell Display Number", indexPath.row)
}
func getFeeds(lastKey: String?) {
print(self.isFetching, "is fetching")
guard !self.isFetching else {
self.previousKey = ""
return
}
self.isFetching = true
print(self.isFetching, "is fetching")
FirebaseModel.fetchPostsWith(last_key: lastKey) { ( d ) in
self.isFetching = false
if let data = d {
if self.feeds.isEmpty { //It'd be, when it's the first time.
self.feeds.append(contentsOf: data)
self.tableView.reloadData()
print("Initial Load", lastKey ?? "no key")
} else {
self.hasFetchedLastPage = self.feeds.count < 2
self.feeds.append(contentsOf: data)
self.tableView.reloadData()
print("Reloaded", lastKey ?? "no key")
}
}
}
}
I want to implement a paging enabled tableView. If you can help this code to be working, it is very appreciated.
You're converting your last_key to a number, while keys are always strings. The error message tells you that the two types are not compatible. This means you must convert your number back to a string in your code, before passing it to the query:
let this = ref.queryOrderedByKey().queryEnding(atValue: last_key).queryLimited(toLast: String(this_key))
let that = ref.queryOrderedByKey().queryLimited(toLast: String(that_key))

Delete a row from a class in Parse - In Swift

I'm trying to make some voting buttons for my film app.
I use Parse, and I've created a new class called Votes_Up. In this class their are 2 columns: User_Voting and Film_VotedFor.
My code below is actioned when the button is pressed. It takes the currentUser and the film object that the button has been pressed against, and adds them to Parse. My database looks like this:
What I need
so they way it currently works, if the user presses the vote button, it adds the info to the DB and adds 1 to the count. When the user presses it again, it just updates the count by taking 1 away.
I would also want to remove the row it would have added to the database, By the User that voted for it. How can I do this??
My code:
#IBAction func upVoteButton(sender: UIButton) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
if PFUser.currentUser() != nil {
if userPressedUpButton == false {
userPressedUpButton = true
let voteUp = PFObject(className: "Votes_Up")
voteUp["User_Voting"] = PFUser.currentUser()
voteUp["Film_VotedFor"] = object!
object!.incrementKey("UpVoteCount")
object!.saveInBackground()
voteUp.saveInBackgroundWithBlock({ (success, error) in
if success == true {
// Object(s) was/were successfully saved
} else if error != nil {
// Display an alert to the user
} else {
// Display an alert to the user - something went wrong
}
})
} else {
userPressedUpButton = false
// I need to removed the row from the class here that was added, as the user has retracted their vote!
object!.incrementKey("UpVoteCount", byAmount: -1)
object!.saveInBackground()
}
} else {
// No user is logged in so they can't vote
performSegueWithIdentifier("Votes_LoginPopup", sender: self)
}
self.tableView.reloadData()
}
Try this:
var query = PFQuery(className:"Votes_Up")
query.whereKey("User_Voting", equalTo:PFUser.currentUser())
query.limit = 1
query.findObjectsInBackgroundWithBlock {
(votesUp: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = votesUp as? [PFObject] {
var firstObject = objects[0]
dispatch_async(dispatch_get_main_queue(),{
// do delete here
firstObject.deleteEventually();
})
}
}
}
or this:
let query = PFQuery(className: "Votes_Up")
query.whereKey("User_Voting", equalTo: PFUser.currentUser())
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects {
object.deleteEventually()
}
}

How to manipulate iOS contacts with SwiftAddressBook?

I'm trying to get all the users contacts and see if they are already singed up in the backend. I'm trying first to get all the contacts using SwiftAddressBook and then I want to edit all the phone numbers and add country code to phone number.
I made this function but it doesn't work, it's only showing phone numbers.
SwiftAddressBook.requestAccessWithCompletion({ (success, error) -> Void in
if success {
if let people = swiftAddressBook?.allPeople {
for person in people {
var phonenumber = String (person.phoneNumbers?.map({$0.value}))
print(phonenumber.characters.last)
if phonenumber.characters.first == "0" {
phonenumber = phonenumber.stringByReplacingCharactersInRange(phonenumber.startIndex..<phonenumber.startIndex.successor(), withString: "+33")
}
print(phonenumber)
}
}
}
else {
print("Fail")
}
})
Well, in first, you should call swiftAddressBook.save() to save the current state of the address book. In second, you are changing a local string variable, which will not affect the address book state. It appears SwiftAddressBook will only make changes to the contacts if you change phoneNumbers array. This should work:
SwiftAddressBook.requestAccessWithCompletion({ (success, error) -> Void in
if success {
if let people = swiftAddressBook?.allPeople {
for person in people {
if let phoneNumbers = person.phoneNumbers {
var phoneNumbersChanged = false
var newPhoneNumbers = [MultivalueEntry<String>]()
for var phonenumber in phoneNumbers {
if phonenumber.value.characters.first == "0" {
phonenumber.value = phonenumber.value.stringByReplacingCharactersInRange(phonenumber.value.startIndex..<phonenumber.value.startIndex.successor(), withString: "+33")
newPhoneNumbers.append(MultivalueEntry(value: phonenumber.value, label: phonenumber.label, id: phonenumber.id))
phoneNumbersChanged = true
} else {
newPhoneNumbers.append(phonenumber)
}
print(phonenumber.value)
}
if phoneNumbersChanged {
person.phoneNumbers = newPhoneNumbers
}
}
}
swiftAddressBook.save()
}
}
else {
print("Fail")
}
})

Resources