I have a tableview in my view controller and i am trying to implement the pull to refresh function. When i pull to refresh the table view does not reload and the data is not updated.
When i print the array print(tempRefresh) inside of my fetchRefresh function, it returns an empty array??
my firebase database looks like this.
override func viewDidLoad() {
super.viewDidLoad()
// refresh the page
refreshControl = UIRefreshControl()
if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
// fallback on older versions
tableView.addSubview(refreshControl)
}
refreshControl.attributedTitle = NSAttributedString(string: "Loading...")
refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
// reload the tabelview
tableView.reloadData()
tableView.delegate = self
tableView.dataSource = self
}
#objc func handleRefresh() {
print("refresh")
beginRefresh()
DispatchQueue.main.async {
self.refreshControl.endRefreshing()
}
}
func fetchRefresh(completion: #escaping(_ comments:[Comments])->()) {
oldCommentsQuery.queryLimited(toLast: 20).observeSingleEvent(of: .value, with: { snapshot in
var tempRefresh = [Comments]()
let commentsSnap = snapshot.childSnapshot(forPath: "comments")
let allComments = commentsSnap.children.allObjects as! [DataSnapshot]
for commentSnap in allComments {
let degree = commentSnap.childSnapshot(forPath: "reply degree").value as? String ?? ""
let name = commentSnap.childSnapshot(forPath: "reply name").value as? String ?? ""
let text = commentSnap.childSnapshot(forPath: "reply text").value as? String ?? ""
let university = commentSnap.childSnapshot(forPath: "reply university").value as? String ?? ""
let photoURL = commentSnap.childSnapshot(forPath: "reply url").value as? String ?? ""
let url = URL(string: photoURL)
let timestamp = commentSnap.childSnapshot(forPath: "timestamp").value as? Double
let lastComment = self.comments.last
if snapshot.key != lastComment?.id {
let newRefresh = Comments(id: snapshot.key, fullname: name, commentText: text, university: university, degree: degree, photoURL: photoURL, url: url!, timestamp: timestamp!)
tempRefresh.insert(newRefresh, at: 0)
//test
print(tempRefresh)
}
}
return completion(tempRefresh)
})
}
func beginRefresh() {
fetchingMore = true
// fetch the comments
fetchRefresh { newComments in
self.comments.append(contentsOf: newComments)
self.endReached = newComments.count == 0
self.fetchingMore = false
self.tableView.reloadData()
}
}
Related
I have a handleRefresh() function that is called when the user refreshes the page. When the refresh happens new comments that were posted are loaded into the tableview.
The problem i have is that when the users refreshes the data in the tableview loads twice so i get the updated comments but with duplicates where it has reloaded the old comments again.
I am a bit stuck on how to fix this.
Here is the code.
var CommentsQuery: DatabaseQuery {
let postRef = Database.database().reference().child("posts")
let postKey = keyFound
let postCommentRef = postRef.child(postKey)
let lastComment = self.comments.last
var queryRef: DatabaseQuery
if lastComment == nil {
queryRef = postCommentRef.queryOrdered(byChild: "timestamp")
} else {
let lastTimestamp = lastComment!.createdAt.timeIntervalSince1970 * 1000
queryRef = postCommentRef.queryOrdered(byChild: "timestamp").queryEnding(atValue: lastTimestamp)
}
return queryRef
}
#objc func handleRefresh() {
CommentsQuery.queryLimited(toLast: 20).observeSingleEvent(of: .value) { snapshot in
var tempComments = [Comments]()
let commentsSnap = snapshot.childSnapshot(forPath: "comments")
let allComments = commentsSnap.children.allObjects as! [DataSnapshot]
for commentSnap in allComments {
let degree = commentSnap.childSnapshot(forPath: "reply degree").value as? String ?? ""
let name = commentSnap.childSnapshot(forPath: "reply name").value as? String ?? ""
let text = commentSnap.childSnapshot(forPath: "reply text").value as? String ?? ""
let university = commentSnap.childSnapshot(forPath: "reply university").value as? String ?? ""
let photoURL = commentSnap.childSnapshot(forPath: "reply url").value as? String ?? ""
let url = URL(string: photoURL)
let timestamp = commentSnap.childSnapshot(forPath: "timestamp").value as? Double
let lastComment = self.comments.last
if snapshot.key == lastComment?.id {
let newComments = Comments(id: snapshot.key, fullname: name, commentText: text, university: university, degree: degree, photoURL: photoURL, url: url!, timestamp: timestamp!)
tempComments.insert(newComments, at: 0)
print("fetchRefresh")
}
}
self.comments.insert(contentsOf: tempComments, at: 0)
self.fetchingMore = false
self.refreshControl.endRefreshing()
self.tableView.reloadData()
}
}
If the self.comments.last is persisted across page reloads, then it seems to be that the problem is that you use queryEnding(atValue: here:
queryRef = postCommentRef.queryOrdered(byChild: "timestamp").queryEnding(atValue: lastTimestamp)
Since timestamp values are incremental (higher values are newer), you want the node with a timestamp higher than the latest value, which you do with queryStarting(atValue: and not with queryEnding(atValue:.
I have a chat feature on my app that updates the table instantly when a user enters new text. Unfortunately when a user enters the text it shows any empty row in the uitableview. When I exit out of the screen and return that new value is now there at the end of the table. So even though it's showing an empty row in the uitableview it's submitting the actual value to the database.
class ConversationViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
//var user = NSDictionary()
var messages = NSDictionary()
var hhmessages = [AnyObject]()
//var messages: [Message] = []
var pictures = [UIImage]()
var avas = [UIImage]()
var avaURL = [String]()
var isLoading = false
var skip = 0
var limit = 50
var images = [UIImage]()
var incoming: [Int] = []
var comments = [String]()
var ids = [String]()
#IBOutlet var replyTxt: UITextView!
#IBOutlet var replyTxt_height: NSLayoutConstraint!
#IBOutlet var replyTxt_bottom: NSLayoutConstraint!
#IBOutlet var replyBtn: UIButton!
var commentsTextView_bottom_identity = CGFloat()
#IBOutlet var tableView: UITableView!
// Table View here + basic configuration
override func viewDidLoad() {
super.viewDidLoad()
// dynamic cell height
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
loadPosts()
replyTxt.layer.cornerRadius = replyTxt.bounds.width / 50
replyTxt.backgroundColor = UIColor.clear
replyTxt.layer.borderColor = UIColor.gray.cgColor
replyTxt.layer.borderWidth = 1.0
let username = messages["sender"] as? String
self.navigationItem.title = username
}
// TABLEVIEW
// Number os cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hhmessages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let colorSmoothGray = UIColor(red: 229/255, green: 229/255, blue: 234/255, alpha: 1)
let colorBrandBlue = UIColor(red: 148 / 255, green: 33 / 255, blue: 147 / 255, alpha: 1)
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
// no picture in the post
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
// shortcuts
let hhpost = hhmessages[indexPath.row]
let text = hhpost["messagetext"] as? String
cell.messageLbl.text = text
return cell
}
// func of loading posts from server
#objc func loadPosts() {
//isLoading = true
let me = user!["username"] as! String
let meid = user!["id"] as! String
print(meid)
print(me)
//print(username)
let uuid = messages["uuid"] as! String
print(uuid)
// accessing php file via url path
let url = URL(string: "http://localhost/message.php")!
// pass information to php file
let body = "username=\(me)&uuid=\(uuid)&recipient_id=\(meid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: String.Encoding.utf8)
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
// launch session
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// no error of accessing php file
// error occured
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
//self.isLoading = false
return
}
do {
// access data - safe mode
guard let data = data else {
Helper().showAlert(title: "Data Error", message: error!.localizedDescription, in: self)
//self.isLoading = false
return
}
// getting content of $returnArray variable of php file
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
// accessing json data - safe mode
guard let posts = json?["messages"] as? [NSDictionary] else {
//self.isLoading = false
return
}
// assigning all successfully loaded posts to our Class Var - posts (after it got loaded successfully)
self.hhmessages = posts
self.tableView.reloadData()
// scroll to the latest index (latest cell -> bottom)
let indexPath = IndexPath(row: self.hhmessages.count - 1, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
// self.isLoading = false
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
//self.isLoading = false
return
}
}
}.resume()
}
// function sending requset to PHP to uplaod a file
func uploadPost() {
// validating vars before sending to the server
guard let user_id = user?["id"] as? String, let username = user?["username"] as? String, let avaPath = user?["ava"] else {
// converting url string to the valid URL
if let url = URL(string: user?["ava"] as! String) {
// downloading all data from the URL
guard let data = try? Data(contentsOf: url) else {
return
}
// converting donwloaded data to the image
guard let image = UIImage(data: data) else {
return
}
// assigning image to the global var
let currentUser_ava = image
}
return
}
let user_id_int = Int(user_id)!
let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
let indexPath = IndexPath(row: hhmessages.count - 1, section: 0)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
replyTxt.text = ""
textViewDidChange(replyTxt)
let recipient = messages["username"] as! String
let rid = String(describing: messages["recipient_id"]!)
let uuid = messages["uuid"] as! String
puuid = UUID().uuidString
// prepare request
let url = URL(string: "http://localhost/messagepost.php")!
let body = "sender_id=\(user_id)&sender=\(username)&text=\(messagetext)&recipient_id=\(rid)&recipient=\(recipient)&uuid=\(uuid)&puuid=\(puuid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: .utf8)
// send request
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// error happened
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
return
}
do {
// converting received data from the server into json format
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
// safe mode of casting json
guard let parsedJSON = json else {
return
}
// if the status of JSON is 200 - success
if parsedJSON["status"] as! String == "200" {
} else {
Helper().showAlert(title: "400", message: parsedJSON["status"] as! String, in: self)
return
}
// json error
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
return
}
}
}.resume()
}
#IBAction func replyBtn_clicked(_ sender: Any) {
if replyTxt.text.isEmpty == false && replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false {
uploadPost()
//tableView.reloadData()
}
}
While appending a new message you are adding a String to the hhmessages array
let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
But in cellForRowAt method you are trying to get the String from hhmessages array using "messagetext" key
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
let hhpost = hhmessages[indexPath.row]
let text = hhpost["messagetext"] as? String
Change
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
to
hhmessages.insert(["messagetext": messagetext] as AnyObject, at: hhmessages.endIndex)
Instead of using array of AnyObject, use a struct
var hhmessages = AnyObject
struct Message {
var uploadpath: URL?
var messagetext: String?
}
var hhmessages = [Message]()
I've been working on a ios App that uses Firebase and GeoFire. I was able to store user coordinates using GeoFire into firebase. I am now trying to load the user details onto a tableview with GeoFire but have been unsuccessful. Without Geofire I was able to load all the user details onto the table, but now it just shows a blank table. Would someone please give me some pointers?
var myQuery: GFQuery?
var geoFireRef: DatabaseReference?
var geoFire: GeoFire?
var user = Auth.auth().currentUser
var filteredUsers = [Users]()
var users = [Users]()
var isSearching = false
override func viewDidLoad() {
super.viewDidLoad()
geoFireRef = Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("user_locations")
geoFire = GeoFire(firebaseRef: geoFireRef!)
let userLat = UserDefaults.standard.value(forKey: "current_latitude") as! String
let userLong = UserDefaults.standard.value(forKey: "current_longitude") as! String
let location:CLLocation = CLLocation(latitude: CLLocationDegrees(Double(userLat)!), longitude: CLLocationDegrees(Double(userLong)!))
myQuery = geoFire?.query(at: location, withRadius: 100)
myQuery?.observe(.keyEntered, with: { (key, location) in
if key != Auth.auth().currentUser?.uid {
// print("KEY:\(String(describing: key)) and location:\(String(describing: location))")
let ref = Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("Users").child(key)
ref.observeSingleEvent(of: .value, with: { (DataSnapshot) in
if let dictionary = DataSnapshot.value as? [String: AnyObject] {
let user = Users()
user.name = DataSnapshot.key
// user.setValuesForKeys(dictionary)
user.name = dictionary["name"] as! String
user.age = dictionary["age"] as! String
user.sex = dictionary["sex"] as! String
user.profileImageUrl = dictionary["profilePicUrl"] as! String
self.users.append(user)
print(user.name, user.age, user.profileImageUrl)
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
})
} else {
print("cannot retrieve users based on location")
}
})
tableView.dataSource = self
tableView.delegate = self
searchBar.delegate = self
searchBar.returnKeyType = UIReturnKeyType.done
tableView.reloadData()
}
I am doing a project in Swift 3 - xcode 8, and I am trying to use core data to save and show some images in a data base table "users".
This image is the user photo in his profile.
Now I've managed to save strings and showing them from core data but I am having problems in working this out with images.
This is what I have so far:
Adding USERS into core data
func addUser() {
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
let newUser = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
if (firstName.text == "" && lastName.text == "" && contact.text == "" && email.text == "") { //if we have a user profile delete it
deleteUser()
} else { // add a new user profile
newUser.setValue(firstName.text, forKey: "firstName")
newUser.setValue(lastName.text, forKey: "lastName")
newUser.setValue(contact.text, forKey: "contact")
newUser.setValue(email.text, forKey: "email")
//newUser.setValue(imageView.image, forKey: "photo")
//let imgUrl = UIImagePickerControllerReferenceURL as! NSURL
let img = UIImage(named: "f.png")
let imgData = UIImageJPEGRepresentation(img!, 1)
newUser.setValue(imgData, forKey: "photo")
print ("Data added in Users")
}
do {
try context.save()
//print("saved!!!")
Alert.show(title: "Success", message: "Profile Saved", vc: self)
} catch {
// print ("Error")
Alert.show(title: "Error", message: "Profile not Saved", vc: self)
}
}
Showing Users from core data
func showUser() {
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
if results.count > 0 {
print("Profile: Data Found:")
for result in results as! [NSManagedObject] {
if let firstNameinData = result.value(forKey: "firstName") as? String{
firstName.text = firstNameinData
print(firstNameinData)
}
if let lastNameinData = result.value(forKey: "lastName") as? String{
lastName.text = lastNameinData
print(lastNameinData)
}
if let contactinData = result.value(forKey: "contact") as? String{
contact.text = contactinData
print(contactinData)
}
if let emailinData = result.value(forKey: "email") as? String{
email.text = emailinData
print(emailinData)
}
if let photoinData = result.value(forKey: "photo") as? UIImage{
imageView.image = photoinData
}
}
} else { // if there is not a user profile
firstName.text = ""
lastName.text = ""
contact.text = ""
email.text = ""
print("Profile : No data found")
}
//print("Loaded!!!")
} catch {
print ("Error Loading")
}
}
I cannot show the image I have saved.
Do you have any tips?
EDIT: Xcode gives me this message "Connection to assetsd was interrupted or assetsd died"
The property photo of Users is (NS)Data, as you do there, converting the
UIImage into NSData.
let img = UIImage(named: "f.png")
let imgData = UIImageJPEGRepresentation(img!, 1)
newUser.setValue(imgData, forKey: "photo")
While when you retrieve the info, you are doing like photo was a UIImage object:
if let photoinData = result.value(forKey: "photo") as? UIImage{
imageView.image = photoinData
}
This is not logical according to previous lines. It should be something like that:
if let imageData = result.value(forKey: "photo") as? NSData {
if let image = UIImage(data:imageData) as? UIImage {
imageView.image = image
}
}
Note: I don't speak Swift, so the proposed code may not compile, but you should get the idea of what's wrong and what's need to be done.
Larme has it almost spot on, but instead of this:
if let image = UIImage(data:imageData) as? UIImage
do this:
if let image = UIImage(data: imageData as Data)
Hope i helps you. work fine for me
var results :[Any] = []
let image = UIImage(named: "image.png")
//this is the line that appears to be wrong
let imageData = UIImagePNGRepresentation(image!) as NSData?
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
// 1
let managedContext =
appDelegate.persistentContainer.viewContext
// 2
let entity =
NSEntityDescription.entity(forEntityName: "Image",
in: managedContext)!
let person = NSManagedObject(entity: entity,
insertInto: managedContext)
// 3
person.setValue(imageData, forKeyPath: "name")
// 4
do {
try managedContext.save()
results.append(person)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
Hope this will help you. First I too had a great confusing of storing the image in core Data.
This is used to save the image in coreData
First create Nsmanaged Object Class
class Item: NSManagedObject {
}
Declare the image as NSData
import CoreData
extension Item {
#NSManaged var image: NSData?
#NSManaged var name: String?
#NSManaged var email: String?
}
Now go the View Controller you want to save the image .
class newViewController: UIViewController ,UIImagePickerControllerDelegate,UINavigationControllerDelegate{
var item : Item? = nil
var imagePicker = UIImagePickerController()
var PassImages = UIImage()
#IBOutlet var name: UITextField!
#IBOutlet var email: UITextField!
#IBOutlet var photoclick: UIButton!
var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
#IBAction func clickaction(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
print("Button capture")
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.sourceType = .photoLibrary
picker.delegate = self //Don't forget this line!
self.present(picker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var selectedImage: UIImage?
if let editedImage = info[.editedImage] as? UIImage {
selectedImage = editedImage
self.image.image = selectedImage!
picker.dismiss(animated: true, completion: nil)
} else if let originalImage = info[.originalImage] as? UIImage {
selectedImage = originalImage
self.image.image = selectedImage!
picker.dismiss(animated: true, completion: nil)
}
}
func imagePickerControllerDidCancel(picker: UIImagePickerController!) {
self.dismiss(animated: true, completion: nil)
}
#IBOutlet var image: UIImageView!=nil
#IBAction func submit(_ sender: Any) {
if name.text != "" && email.text != ""
{
let entityDescription = NSEntityDescription.entity(forEntityName: "Table", in: context)
let item = Item(entity: entityDescription!, insertInto: context)
item.name = name.text
item.email = email.text
item.image = image.image!.pngData()! as NSData
do {
try context.save()
print("saved this moc")
} catch {
return
}
let UserDetailsVc = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.navigationController?.pushViewController(UserDetailsVc, animated: true)
}
else
{
print("mail check")
let alertController1 = UIAlertController (title: "Fill Email id", message: "Enter valid email", preferredStyle: UIAlertController.Style.alert)
alertController1.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController1, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
if item != nil {
name.text = item?.name
email.text = item?.email
image.image = UIImage(data: (item?.image)! as Data)
}
}
This controller is used to fetch everything
class ViewController: UIViewController ,UITableViewDataSource,UITableViewDelegate,NSFetchedResultsControllerDelegate{
var userarray: [Table] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userarray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
let name = userarray[indexPath.row]
cell.username.text = name.name
cell.showImage?.image = UIImage(data: (name.image)!)
return cell
}
#IBOutlet var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
override func viewWillAppear(_ animated: Bool) {
fetchData()
}
func fetchData(){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
userarray = try context.fetch(Table.fetchRequest())
print(userarray,"user")
}catch{
print("error")
}
}
}
I am having a hard time trying to figure out, how I can change/update a specific part of my firebase database through swift. To give you an example of how my firebase database is structured, here you have a photo:
I am trying to update the likesForPost +1 everytime someone hits the like button that I have in my tableViewController. The important part is that every likesForPost should not be updates, just the one where the button is. I hope you understand my situation and that you can help me :-)
My struct
struct Sweet {
let key: String!
let content: String!
let addedByUser: String!
let profilePhoto: String!
var likesForPost: String!
let itemRef: FIRDatabaseReference?
init (content: String, addedByUser: String, profilePhoto: String!, likesForPost: String!, key: String = "") {
self.key = key
self.content = content
self.addedByUser = addedByUser
self.profilePhoto = profilePhoto
self.likesForPost = likesForPost
self.itemRef = nil
}
init (snapshot: FIRDataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref
if let theFeedContent = snapshot.value!["content"] as? String {
content = theFeedContent
} else {
content = ""
}
if let feedUser = snapshot.value!["addedByUser"] as? String {
addedByUser = feedUser
} else {
addedByUser = ""
}
if let feedPhoto = snapshot.value!["profilePhoto"] as? String! {
profilePhoto = feedPhoto
} else {
profilePhoto = ""
}
if let feedLikes = snapshot.value!["likesForPost"] as? String! {
likesForPost = feedLikes
} else {
likesForPost = "0"
}
}
func toAnyObject() -> AnyObject {
return ["content":content, "addedByUser":addedByUser, "profilePhoto":profilePhoto!, "likesForPost":likesForPost]
}
}
My UITableViewController
import UIKit
import FirebaseDatabase
import FirebaseAuth
import FBSDKCoreKit
class feedTableViewController: UITableViewController {
#IBOutlet weak var loadingSpinner: UIActivityIndicatorView!
var facebookProfileUrl = ""
var dbRef: FIRDatabaseReference!
var updates = [Sweet]()
override func viewDidLoad() {
super.viewDidLoad()
loadingSpinner.startAnimating()
dbRef = FIRDatabase.database().reference().child("feed-items")
startObersvingDB()
}
func startObersvingDB() {
dbRef.observeEventType(.Value, withBlock: { (snapshot: FIRDataSnapshot) in
var newUpdates = [Sweet]()
for update in snapshot.children {
let updateObject = Sweet(snapshot: update as! FIRDataSnapshot)
newUpdates.append(updateObject)
}
self.updates = newUpdates
self.tableView.reloadData()
}) { (error: NSError) in
print(error.description)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addToFeed(sender: AnyObject) {
let feedAlert = UIAlertController(title: "New update", message: "Enter your update", preferredStyle: .Alert)
feedAlert.addTextFieldWithConfigurationHandler { (textField:UITextField) in
textField.placeholder = "Your update"
}
feedAlert.addAction(UIAlertAction(title: "Send", style: .Default, handler: { (action:UIAlertAction) in
if let feedContent = feedAlert.textFields?.first?.text {
if let user = FIRAuth.auth()?.currentUser {
let name = user.displayName
//let photoUrl = user.photoURL
let accessToken = FBSDKAccessToken.currentAccessToken()
if(accessToken != nil) //should be != nil
{
let req = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id"], tokenString: accessToken.tokenString, version: nil, HTTPMethod: "GET")
req.startWithCompletionHandler({ (connection, result, error : NSError!) -> Void in
if(error == nil)
{
let userId: String! = result.valueForKey("id") as? String!
let userID = userId
self.facebookProfileUrl = "http://graph.facebook.com/\(userID)/picture?type=large"
let likes = "0"
let feed = Sweet(content: feedContent, addedByUser: name!, profilePhoto: self.facebookProfileUrl, likesForPost: likes)
let feedRef = self.dbRef.child(feedContent.lowercaseString)
feedRef.setValue(feed.toAnyObject())
}
else
{
print("error \(error)")
}
})
}
// LAV FEEDCONTENT OM TIL OGSÅ AT MODTAGE PROFIL BILLEDE URL I STRING OG GIV SÅ facebookProfileUrl STRING LIGE HERUNDER I feed
} else {
// No user is signed in.
}
}
}))
self.presentViewController(feedAlert, animated: true, completion: nil)
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return updates.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let update = updates[indexPath.row]
//cell.textLabel?.text = update.content
//cell.detailTextLabel?.text = update.addedByUser
cell.nameLabel.text = update.addedByUser
cell.updateLabel.text = update.content
cell.likesLabel.text = "\(update.likesForPost) hi-fives"
if update.profilePhoto! != "" {
if let url = NSURL(string: update.profilePhoto!) {
if let data = NSData(contentsOfURL: url) {
cell.picView.image = UIImage(data: data)
cell.picView.layer.cornerRadius = cell.picView.frame.size.width/2
cell.picView.clipsToBounds = true
}
}
} else {
print("Empty facebookProfileUrl")
}
loadingSpinner.stopAnimating()
return cell
}
}
Modify your struct to include one more variable (lets say let path : String!)that will include the value of the node key retrieved from your DB(megaTest or test).
Your Struct
struct Sweet {
let key: String!
let content: String!
let addedByUser: String!
let profilePhoto: String!
var likesForPost: String!
let itemRef: FIRDatabaseReference?
let path : String!
init (content: String, addedByUser: String, profilePhoto: String!, likesForPost: String!, key: String = "",dataPath : String!) {
self.key = key
self.content = content
self.addedByUser = addedByUser
self.profilePhoto = profilePhoto
self.likesForPost = likesForPost
self.itemRef = nil
self.path = dataPath
}
init (snapshot: FIRDataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref
path = key
if let theFeedContent = snapshot.value!["content"] as? String {
content = theFeedContent
} else {
content = ""
}
if let feedUser = snapshot.value!["addedByUser"] as? String {
addedByUser = feedUser
} else {
addedByUser = ""
}
if let feedPhoto = snapshot.value!["profilePhoto"] as? String! {
profilePhoto = feedPhoto
} else {
profilePhoto = ""
}
if let feedLikes = snapshot.value!["likesForPost"] as? String! {
likesForPost = feedLikes
} else {
likesForPost = "0"
}
}
func toAnyObject() -> AnyObject {
return ["content":content, "addedByUser":addedByUser, "profilePhoto":profilePhoto!, "likesForPost":likesForPost,"pathInTheDB" : path]
}
}
In cellForIndexPath just add this
cell. pathDB = self.structArray![indexPath.row].path
Modify your customCell class like this
class customTableViewCell : UITableViewCell{
var pathDB : String! //megaTest or test
#IBAction func likeBtn(sender : UIButton!){
//Update like's
}
}
For updating the value you can use either runTransactionBlock:-
FIRDatabase.database().reference().child(pathDB).child("likesForPost").runTransactionBlock({ (likes: FIRMutableData) -> FIRTransactionResult in
// Set value and report transaction success
likes.value = likes.value as! Int + 1
return FIRTransactionResult.successWithValue(likes)
}) { (err, bl, snap) in
if let error = error {
print(error.localizedDescription)
}
}
Or observe that node with .observeSingleEventOfType, retrieve the snap and then update
let parentRef = FIRDatabase.database().reference().child(pathDB).child("likesForPost")
parentRef.observeSingleEventOfType(.Value,withBlock : {(snap) in
if let nOfLikes = snap.value as? Int{
parentRef.setValue(nOfLikes+1)
}
})