Adding two of the same values to array instead of one - swift - ios

I am trying to make a search bar, where you can search for users names. The cell is showing two things - and image and a label.
The label is showing the users name and the image is showing the profile picture. The image needs the user userID to display his/her picture.
The countryAndCode contains the users userID called country, and the users name called code.
My problem is that it is adding the first user twice and I do not know why or how to change it.
Here is the relevant code, let me know if you would like to see more:
func startObersvingDB() {
FIRDatabase.database().reference().child("UserInformation").observeEventType(.ChildAdded, withBlock: { snapshot in
let title = snapshot.value!["usersUID"] as? String
let name = snapshot.value!["userName"] as? String
self.tableData.append(title!)
self.tableDataNames.append(name!)
for i in 0..<self.tableData.count {
print(self.tableDataNames.count)
print(self.tableData.count)
self.countryAndCode.append((self.tableData[i], code: self.tableDataNames[i]))//this shows error in XCode some times
//if the above code doesn't compile then use the below code
print("DONE")
print(self.countryAndCode)
}
self.tableView.reloadData()
})
}

Related

Changing app icon doesn't work when saving user defaults

In a secondary view controller in my app, I have a table of icons to change to, like the Reddit app Apollo.
In my main view controller, I am using user defaults to save two labels text and the view background color. Without any user default saving at all, when tapping on one of the table rows, I am able to change the app icon freely with these lines:
let appIconService = AppIconService()
appIconService.changeAppIcon(to: .goldAppIcon)
For saving user defaults: When a button is pressed on screen it randomly selects a string from an array and sets one of the two label.text, then randomly selects a UIColor and sets the view.backgroundcolor. I then save those with the "saveLastQuote()" function, and then call the "checkForLastQuote()" function in viewDidLoad() to grab from user defaults:
let defaults = UserDefaults.standard
func saveLastQuote() {
defaults.set(randomText.text!, forKey: Keys.savedQuote)
defaults.set(nameText.text!, forKey: Keys.savedName)
defaults.set(self.view.backgroundColor, forKey: Keys.savedBackgroundColor)
}
func checkForLastQuote() {
let lastQuote = defaults.value(forKey: Keys.savedQuote) as? String ?? "\"Quote\""
let lastName = defaults.value(forKey: Keys.savedName) as? String ?? ""
let lastBackgroundColor = defaults.color(forKey: Keys.savedBackgroundColor)
randomText.text = lastQuote
nameText.text = lastName
self.view.backgroundColor = lastBackgroundColor ?? Colors.black
}
For some reason when I have the saving user defaults code in the main ViewController.swift, when I tap on a row to change the icon on the other screen, I get this dialog box (The screenshot below) indicating to me that it has changed, but when I close the app and reopen, it always stays at its original app icon (Black and white version of the gold one in the screenshot)
EDIT: When I build and run the app on my device (Which is where I do all my testing for the app), the app's icon DOES change to the new one I clicked in the table view, then continues to not change until I build and run again.
Do I need to save the icon I am changing now since I am using user defaults to append other items? Or possibly grab the changed icon it normally saves by itself from user defaults and set it? I don't know why I would be getting this behavior. Pretty confused about it.

attach Firebase listeners to tableViewCell

I have a chat feature in an iOS app. the chat previews are presented in a tableView and I am using a class for the TableView cells themselves. I want to listen for new messages so I can put a "new Message" label on the cells. The relevant parts of the tableView Cell are:
var chat: Chat! {
didSet {
self.updateUI()
self.observeNewMessages()
}
}
extension ChatTableViewCell {
func observeNewMessages() {
let chatMessageIdsRef = chat.ref.child("messageIds")
chatMessageIdsRef.observe(.childAdded, with: { snapshot in
let messageId = snapshot.value as! String
DatabaseReference.messages.reference().child(messageId).observe(.childAdded, with: { snapshot in
//let message = Message(dictionary: snapshot.value as! [String : Any])
print("looks like there is a new message") //works
self.messageLabel.text = "New Message!"
//self.delegate?.newMessage()
})
})
}
}
The print statement is there to test the listener. The problem I am having is when the table view loads and the cells get created, observeNewMessages() is executing the print statement regardless of whether there were new messages. It is just reading the old children that are already there first? Obviously this is going to cause the message label to always read "New Message." I'm not too good with Firebase so is there a better Firebase function to use or a better way to do this?
*I am using 2 queries because the Message dictionary will allow me to see if the current user made the message or not. The delegate is there because my next step will be to reload the tableview -- as it is now, this will also cause an infinite print statement loop...

Updating Table View after Updating Values in Firebase

I'm able to successfully update my entries in Firebase, for it shows up on the console, but not the table view. If I restart my app the changes will then show, but I want them to show immediately.
My approach is to edit the array that populates the tableview as soon possible under the "ChildChanged" notification.
ref.observeEventType(.ChildChanged, withBlock: { (snapshot) in
print("One of the entries were changed so we're reloading the table view")
if let firstname = snapshot.value?.objectForKey("firstname"), lastname = snapshot.value?.objectForKey("lastname")
{
let fullname = "\(firstname) \(lastname)"
names[I_Need_This_Index] = fullname
dispatch_async(dispatch_get_main_queue())
{
self.tableView.reloadData()
}
}
}, withCancelBlock: nil)
As you can see, I just need to locate index of what I need, for I already have the "fullname" value which is the edited value that I wish to update the table view with.
How would I go about doing that?
You need to lookup the index using the key of the changed child. Therefore a dictionary could be set up initially to map the keys for all children to the index of your tableview cell when receiving all values.
Edit:
If you need the old value itself you have to obtain the initial change snapshot yourself.

Display a particular user and all their information stored on parse on a different View Controller in Swift

In my app each user sets up a profile page and all this info is stored on Parse. When the current user hits a button it segues to a tableViewController that displays in cells all the other users on the app. In each cell there is a button which the user presses to view the full profile page of the user that they have selected. I have a VC set up to hold all the info I just don't know how to display the particular user that the current user has selected into it. How do I single out the chosen users information? I have read the Parse documentation on relational queries but I can't seem to get my head around it. https://parse.com/docs/ios/guide#queries-relational-queries
So in finer detail basically all my users are displaying on a VC. It has name and profile picture, when the user clicks on the info button beside a certain user it should open a new screen and display all of this users information stored on Parse.
I have tried creating a static outside the class
struct Data { var OtherName:String! var id:String! }
And then in my ViewDidLoad:
let query = PFQuery(className: "_User")
// otherQuery.orderByDescending("createdAt")
query.whereKey("username", notEqualTo:PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock { (users: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// success
print(users!.count)
for user in users! {
self.imageFiles.append(user["image"] as! PFFile)
self.instrumentText.append(user["instrument"] as! String)
self.nameText.append(user["name"] as! String)
self.ageText.append(user["age"] as! String)
// self.locationText.append(user["location"] as! PFGeoPoint)
var singleData = Data()
singleData.id = user.objectId
singleData.OtherName = user["name"] as! String
print("\(singleData)")
} // users
Then on the VC that the info button segues to I am trying to call it and upload each label with just the user that was selected.
self.userName.text = "" as String
But the "" is staying blank.
Then I was thinking maybe if I add that when the more info button is pressed that the user it was pressed on gets chosen and is added to a chosen string on Parse and then I just have to call the user from the chosen string when I am on the chosen users profile page and call the info that way and then when the user clicks the back button the user is no longer chosen. It just seems like I would be adding and taking away a lot of users to "chosen" in Parse is there a better way?
I am able to display all the users info but how do I just display a chosen user from Parse without using the objectId because at the top of each cell it will return a different user here each time depending on settings previously set on a different VC such as only show users in a certain age bracket etc. I know I must set an Id of some sort on button touched but I am at a complete loss. The only online help out there that I can find is set for other languages eg. https://parse.com/docs/js/guide#users-querying>
So I guess my question is :
1.Does anyone know a tutorial they could point me towards.
2.Does anyone know how I even get started and I can go from there myself.
3.Can anyone help?
*Swift and Parse newbie little to no experience in other languages.
New code in firstVC:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "userProfileDetailsSegue" {
if let indexPath = resultsPageTableView.indexPathForSelectedRow {
let controller = (segue.destinationViewController) as! UserProfileDetailsViewController
***error here: UserProfileDetailsViewController.userToShowDetail = indexPath.row
//line above is the one I can't get to work it needs to equal to the cell selected?
}
}
}
New Code in destinationVC:
var userToShowDetail: PFUser? {
didSet {
self.configureView()
}
}
func configureView() {
// Update the user interface for the detail item.
if let userToShowDetail: PFUser = self.userToShowDetail {
if let label = self.userName {
nameText.append(userToShowDetail["name"] as! String)
// self.nameText.append(user["name"] as! String)
}
}
}
You're going to need to do a couple of things for this to work. First, in the view controller that you're using to show another user's information, you need to set a property like var userToShowDetail: PFUser?. Then in your view with all of the users of your app, you need to create a segue to bring them from the current view to the detail view. Assuming you're using a TableView, you can connect just one prototype cell to the detail view you're trying to navigate. Then you'll need to override prepareForSegue and set the new view controller's user equal to the user at the row that was selected. I don't know how you're storing your objects of user's of your app, but you should probably be able to do something like this.
override fun prepareForSegue(segue: UIStoryboardSegue) {
if segue.identifer == "segueToShowDetailInfo" {
//get the index path for the row that was selected
let indexPath = self.tableView.indexPathForSelectedRow()
//get the PFUser object for that particular row
let userToShow = self.appUsers[indexPath.row]
//create your new view controller
let newVc = segue.destinationViewController as! DestinationVC
//assign the new vc's property to your object
newVc.userToShowDetail = userToShow
}
}
But in your query, you probably shouldn't have a separate array of the the different parts of the user's data. You should just make one array, call it var appUsers = [PFUser]() and then when you get a user back in your query, just say:
for user in users! {
self.appUsers.append(user) as! PFUser
}
There, now you have a whole array of objects that holds a reference to every user. When someone is using your app, and selects a cell, then you can perform the prepare for segue method as above.
Note that I also noticed you have a didSet on your variable in your new view controller. Calling a function to update the UI after this variable is set will not work, and may crash, because the view controller doesn't have a window yet.

querying data and images into a tableview from parse.com using swift

I'm looking to query data and images into a tableview using swift but, I can't seem to find any tutorials or anything showing how to do it. In my parse class I have a class named Products and in that class I have a column called productName, productImage, and productDescription. Than in my table view I have it where it shows the Image and the productName. Than it's suppose to when you click on the cell query over to a viewController to show the Image, the name and the description in a textView. If someone could please give me a hand that would be much appreciated.!
// Display product image
var initialThumbnail = UIImage(named: "question")
cell.ProductImage.image? = initialThumbnail!
if let thumbnail = object?["productImage"] as? PFFile {
cell.ProductImage.file = thumbnail
cell.ProductImage.loadInBackground()
}
It seems that there is something wrong with this code because when I run my app it shows just my question marked picture and not the image from parse.
Update:
I was able to have my pictures show up i didn't have the UIImage in the right class. However I still can't get the image to show up with the other data in the view controller after you click on the cell. only the description and name show up. Any ideas?
This is for the image i posted:vvvvvv
Pretty sure i have to add something here but not really sure what to get the image to query over when the product is selected from the table view
Update: Found out what the problem was. I added this code to it and it works now.
if let object = currentObject {
productName.text = object["productName"] as? String
productDescription.text = object["productDescription"] as! String var initialThumbnail = UIImage(named: "question")
ProductImage.image? = initialThumbnail!
if let thumbnail = object["productImage"] as? PFFile {
ProductImage.file = thumbnail
ProductImage.loadInBackground()
have a look at: https://parse.com/docs/ios/guide#user-interface-pfquerytableviewcontroller, this is Parses own user interface which produces a table view from a parse query. It also explains how you can add a thumbnail to the cell. Each cell will contain the object so you could easily segue to the image the cell represents. I hope this helps!

Resources