I am trying to show an information which is in Core Data, on UITableViewCell.
I could get the information, but the information wasn't shown on UITableViewCell.
When I set the information on CoreData, I use Modal View then.
I tried to use UITableView.reload() but I couldn't show the information on UITableViewCell.
Please let me know how to show the information when I back from modal view.
This class is about showing the information on UItableView.
import UIKit
import CoreData
protocol FriendListTableViewDelegate {
func reloadTable()
}
class FriendListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, FriendListTableViewDelegate{
#IBOutlet weak var friendListTableView: UITableView!
var friends:[FriendBasicInfo] = []
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
// Disable to effect the reload
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadTable()
}
// fetch the information from CoreData
func getData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
friends = try context.fetch(FriendBasicInfo.fetchRequest())
} catch {
print("error")
}
}
func reloadTable() {
friendListTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friends.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let friendCell = tableView.dequeueReusableCell(withIdentifier: "FriendListCell") as! FriendListTableViewCell
let friendName = friendCell.viewWithTag(1) as? UILabel
let friendImage = friendCell.viewWithTag(2) as? UIImageView
friendName?.text = friends[indexPath.row].name
friendImage?.image = friends[indexPath.row].photo?.toImage()
return friendCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
This class is to get the information from CoreData
import UIKit
import XLPagerTabStrip
import Eureka
import CoreData
import ImageRow
class InputFriendInforViewController: FormViewController, IndicatorInfoProvider {
var itemInfo: IndicatorInfo = "Info"
var friendPhoto: UIImage?
var friendName: String = ""
var friendBirthday: Date?
var friendGender: String = ""
var friendListTableViewDelegate: FriendListTableViewDelegate!
override func viewDidLoad() {
super.viewDidLoad()
form +++
Section("Friend Information")
<<< ImageRow(){
$0.title = "Image"
$0.sourceTypes = [.PhotoLibrary, .SavedPhotosAlbum, .Camera]
$0.value = UIImage(named: "noImage")
$0.onChange { [unowned self] row in
self.friendPhoto = row.value!
}
}
<<< TextRow(){ row in
row.title = "Name"
row.placeholder = "Enter Name here"
}.onChange { name in
self.friendName = name.value!
}
<<< DateRow(){ row in
row.title = "Birthday"
row.value = Date(timeIntervalSinceReferenceDate: 0)
}.onChange {date in
self.friendBirthday = date.value!
}
<<< PushRow<String>(){row in
row.title = "Gender"
row.options = ["Male","Female","Other"]
}.onChange {gender in
self.friendGender = gender.value!
}
+++ Section()
<<< ButtonRow() {
$0.title = "SAVE"
}.onCellSelection {_, _ in
self.saveInfo()
}
}
// MARK: - IndicatorInfoProvider
func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
return itemInfo
}
// save friend Info for Core Data
func saveInfo (){
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let friendEntity = NSEntityDescription.entity(forEntityName: "FriendBasicInfo", in: managedContext)!
let friendInfo = NSManagedObject(entity: friendEntity, insertInto: managedContext)
// make unique user ID
let friendUid = NSUUID().uuidString
// Image Data UIImage to png Data
let pngImage = self.friendPhoto?.toPNGData()
friendInfo.setValue(friendUid, forKey: "userID")
friendInfo.setValue(pngImage, forKey: "photo")
friendInfo.setValue(self.friendName, forKey: "name")
friendInfo.setValue(self.friendBirthday, forKey: "birthday")
friendInfo.setValue(self.friendGender, forKey: "gender")
do {
try managedContext.save()
self.dismiss(animated: true, completion:nil)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
This class is about UITableViewCell
import UIKit
class FriendListTableViewCell: UITableViewCell {
#IBOutlet weak var sampleImageView: UIImageView!
#IBOutlet weak var sampleLabel:UILabel!
}
V/r,
As you are using an extra data source array just reloading the table view doesn't consider the new inserted item.
There are a few options
Use NSFetchedResultsController. It updates the UI automatically when the context was saved.
On dismiss insert the new item into the data source array and a new row into the table view.
Observe NSManagedObjectContextDidSaveNotification and insert the item as described in 2.
Refetch the entire data and reload the table view.
The options are in order of efficiency. Version 1 is the most efficient one.
Side note:
viewWithTag is horribly old-fashioned. You got outlets, use them for example
cell.sampleLabel!.text = friends[indexPath.row].name
Your FriendListViewController TableView will reflect any updates to any FriendBasicInfo Entity which was fetched within getData() method. To present a new inserted FriendBasicInfo Entities to the database you have to execute a new fetch with getData() method.
Solution:
func reloadTable() {
getData()
friendListTableView.reloadData()
}
Alternative solution
Advanced monitoring of a fetched entities can be done with NSFetchedResultsController Delegate, this controller will automatically update the FriendListViewController tableview for any updated, inserted or deleted entities.
Related
I just began to learn Firebase a week ago, but right now I am facing a problem of not able to load image from Firebase to my TableViewCell. I can retrieve data such as text information and the URL of the image from Firebase Realtime Database but not able to make use of those URL in order to fire up image on the TableViewCell. May you all help me identify the problems? I can retrieve everything such as text information as well as the image URL but how can I make the image pop up on the cell? All your help would be highly appreciate!
This is the ViewController that responsible to display the TableViewCell
import UIKit
import Firebase
import FirebaseStorage
class NewsFeedViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var rubthort:String = ""
var linkRub:String?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrItem.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mycell", for: indexPath) as! NewsFeed
// textlabel
// detailtextlabel
cell.textLabel?.text = arrItem[indexPath.row].name
cell.detailTextLabel?.text = arrItem[indexPath.row].price
//cell.imageView?.image = UIImage(named: "flower")
// Get image
let id = RetrieveData()
if let imageLink = self.linkRub {
let url = URL(string: imageLink)
//let data = NSData(contentsOf: url!)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
// download hit an error so return out
if error != nil {
print(error)
return
}
DispatchQueue.main.async {
cell.imageView?.image = UIImage(data: data!)
}
}.resume()
}
return cell
}
let ref = Database.database().reference()
// Array of PlasticItem
var arrItem = [RetrieveData]()
#IBOutlet weak var tblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
retrieveData()
} // Ends of viewDidLoad
func retrieveData() {
// Getting a node from database
let retRef = ref.child("item/electronic")
// Observing data changes
retRef.observe(DataEventType.value) { (dataSnapshot) in
// Remove array item everytime there is a new reference to the data in Firebase
self.arrItem.removeAll()
// Check if there are any children or second object inside the parent object
if dataSnapshot.childrenCount > 0 {
// Loop over all children's object
for post in dataSnapshot.children.allObjects as! [DataSnapshot] {
let object = post.value as! [String: Any]
let getName = object["name"] as! String
let getPrice = object["price"] as! String
let getImage = object["itemURL"] as! String
print(getName)
print(getPrice)
print(getImage)
self.linkRub = getImage
self.arrItem.append(RetrieveData(cat: "", name: getName, price: getPrice, rub: getImage))
}
self.tblView.reloadData()
}// Ends of if statement
else if dataSnapshot.childrenCount == 0{
print("No Data Found")
}
} // Ends of retRef.observe
} // Ends of retrieveData()
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
This is the model struct
import Foundation
import UIKit
struct RetrieveData{
var cat: String
var name: String
var price: String
var rub: String?
init(){
self.cat = ""
self.name = ""
self.price = ""
self.rub = ""
}
init(cat:String, name:String, price:String, rub: String){
self.cat = cat
self.name = name
self.price = price
self.rub = rub
}
}
I'm trying to learn iOS programming so I thought it would be a good idea to emulate instagrams feed. Everyone uses this basic feed and I would like to know how to do it.
The basic idea is to have one image/text post show up in a single column. Right now I have a a single image to be shown.
I'm currently extracting the image url correctly from firebase. The only issue is that my CollectionView still is showing up empty. I started this project months ago and I forget where the tutorial is at. Please help me fill in the blanks. Here is the code:
import UIKit
import SwiftUI
import Firebase
import FirebaseUI
import SwiftKeychainWrapper
class FeedViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var collectionview: UICollectionView!
//var posts = [Post]()
var posts = [String](){
didSet{
collectionview.reloadData()
}
}
var following = [String]()
var posts1 = [String]()
var userStorage: StorageReference!
var ref : DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
posts1 = fetchPosts()
//let myIndexPath = IndexPath(row: 0, section: 0)
//collectionView(collectionview, cellForItemAt: myIndexPath)
//print(self.posts1.count)
}
func fetchPosts() -> [String]{
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("posts")
let uids = Database.database().reference().child("users")
uids.observe(DataEventType.value, with: { (snapshot) in
let dict = snapshot.value as! [String:NSDictionary]
for (_,value) in dict {
if let uid = value["uid"] as? String{
self.following.append(uid)
}
}
ref.observe(DataEventType.value, with: { (snapshot2) in
let dict2 = snapshot2.value as! [String:NSDictionary]
for(key, value) in dict{
for uid2 in self.following{
if (uid2 == key){
for (key2,value2) in value as! [String:String]{
//print(key2 + "this is key2")
if(key2 == "urlToImage"){
let urlimage = value2
//print(urlimage)
self.posts1.append(urlimage)
self.collectionview.reloadData()
print(self.posts1.count)
}
}
}
}
}
})
})
//ref.removeAllObservers()
//uids.removeAllObservers()
print("before return")
print(self.posts1.count)
return self.posts1
override func viewDidLayoutSubviews() {
collectionview.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) ->Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts1.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PostCell", for: indexPath) as! PostCell
cell.postImage.sd_setImage(with: URL(string: posts1[indexPath.row]))
//creating the cell
//cell.postImage.downloadImage(from: self.posts[indexPath.row])
// let storageRef = Storage.storage().reference(forURL: self.posts[indexPath.row].pathToImage)
//
//
print("im trying")
//let stickitinme = URL(fileURLWithPath: posts1[0])
//cell.postImage.sd_setImage(with: stickitinme)
//cell.authorLabel.text = self.posts[indexPath.row].author
//cell.likeLabel.text = "\(self.posts[indexPath.row].likes) Likes"
return cell
}
#IBAction func signOutPressed(_sender: Any){
signOut()
self.performSegue(withIdentifier: "toSignIn", sender: nil)
}
#objc func signOut(){
KeychainWrapper.standard.removeObject(forKey:"uid")
do{
try Auth.auth().signOut()
} catch let signOutError as NSError{
print("Error signing out: %#", signOutError)
}
dismiss(animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
UPDATE
The observe call is not updating the value of posts (the dictionary). Once the observe call exits, the value of posts is set back to empty.
PostCell class as asked:
import UIKit
class PostCell: UICollectionViewCell {
#IBOutlet weak var postImage: UIImageView!
#IBOutlet weak var authorLabel: UILabel!
#IBOutlet weak var likeLabel:UILabel!
#IBOutlet weak var likeBtn:UIButton!
#IBOutlet weak var unlikeBtn:UIButton!
#IBAction func likePressed (_ sender: Any){
}
#IBAction func unlikePressed(_sender: Any){
}
}
I think the problem is:
Your collectionView dataSource is called only once. Since the image url loading is asynchronous, you will need to refresh your collectionview every time new data is appended to your datasource array like this:
self.posts.append(urlimage)
collectionView.reloadData()
or:
var posts = [UIImage](){
didSet{
collectionView.reloadData()
}
}
Hope this helps.
Edit update:
Regarding the asynchronous calls, i think you should use escaping closure that runs the code block once the network request receives a response.
First separate the network call functions like:
func fetchUsers(completion: #escaping(_ dictionary: [String: NSDictionary])->()){
let uid = Auth.auth().currentUser!.uid
let uids = Database.database().reference().child("users")
uids.observe(DataEventType.value, with: { (snapshot) in
let dict = snapshot.value as! [String:NSDictionary]
completion(dict)
})
}
func fetchURLS(completion: #escaping(_ dictionary: [String: String])->()){
let ref = Database.database().reference().child("posts")
ref.observe(DataEventType.value, with: { (snapshot2) in
let dict2 = snapshot2.value as! [String:String]
completionTwo(dict2)
})
}
Then, the parsing functions:
func parseUsers(dictionary: [String: NSDictionary]){
for (_,value) in dictionary {
if let uid = value["uid"] as? String{
self.following.append(uid)
}
}
fetchURLS { (urlDictionary) in
self.parseImageURLS(dictionary: urlDictionary)
}
}
func parseImageURLS(dictionary: [String: String]){
for(key, value) in dictionary{
for uid2 in self.following{
if (uid2 == key){
for (key2,value2) in value as! [String:String]{
//print(key2 + "this is key2")
if(key2 == "urlToImage"){
let urlimage = value2
//print(urlimage)
self.posts1.append(urlimage)
self.collectionview.reloadData()
print(self.posts1.count)
}
}
}
}
}
}
Then you add:
fetchUsers { (usersDictionary) in
self.parseUsers(dictionary: usersDictionary)
}
in viewDidLoad()
Hope this solves your problem. On a side note: I recommend using models and separating the network calls in a different file. Feel free to ask any questions.
I figured out how to do it after more searching.
I was incorrectly assuming that the CollectionView is loaded after the viewDidLoad() function is done. The helper classes for a CollectionView are called to a call of reloadData.
I observed that my reloadData call wasn't being called. In order to make this work, I add 2 lines of code to the viewDidLoad function:
collectionview.delegate = self
collectionview.dataSource = self
With this change, the images now load.
I can load my current tableview data onto the database and then print out the new data onto my console but can't get the new data back into the tableview and I'm tearing my hair out because I know it should be simple!
I've tried all sorts of things but I just can't figure out where I'm going wrong.
//Saves to database without any problems
//Class
var ref: DatabaseReference!
//ViewDidLoad
ref = Database.database().reference()
func save()
{
let ref = Database.database().reference(withPath: "Admin")
let adding = ref.child(me)
let addData: [String: [String]] = ["addJokes": data]
adding.setValue(addData)
{
(error:Error?, ref:DatabaseReference) in
if let error = error
{
print("Data could not be saved: \(error).")
}
else
{
print("Data saved successfully!")
}
}
}
Can print out the database data to my console but can't get it into my tableview
let ref = Database.database().reference(withPath: "Admin")
ref.observe(.value, with:
{
(snapshot) in
let new = snapshot.value as? String
print(snapshot.value as Any)
if let newData = new
{
self.data.append(newData)
self.mainTable.reloadData()
}
})
Update
TableView details-
TableView Class Ext
extension TableView: UITableViewDataSource, UITableViewDelegate
{
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if isSearching {
return filteredArray.count
}
else
{
return data.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var array: String?
if isSearching
{
array = filteredArray[indexPath.row]
}
else
{
array = data[indexPath.row]
}
let cell = mainTable.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as UITableViewCell
cell.textLabel?.text = array
return cell
}
TableView Class-
class TableView: UIViewController
{
let cellId = "cellId"
var filteredArray = [String]()
var ref: DatabaseReference!
var data = [
"""
multiple line
data array
"""
]
lazy var mainTable: UITableView =
{
let table = UITableView()
table.translatesAutoresizingMaskIntoConstraints = false
table.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
return table
}()
override func viewDidLoad() {
super.viewDidLoad()
mainTable.delegate = self
mainTable.dataSource = self
}
Console prints exactly what I want back into my tableview. Turning print function into results is usually the easy part.
The problem lies in let new = snapshot.value as? String. Here, new is null thus if let newData = new is always false and if block won't be executed. First, check snapshot.value's data type and value then use it accordingly.
I have singleton shopping cart in my project like this var fromSharedFood = SingletonCart.sharedFood.food. I am getting all food data from MainVC to DetailVC -> MyCartVC. I have table view in MainVC. I want to save MainVC table view datas to CoreData.
My project was offline. Now, it communicates with web api. I used Singleton for data transition from MainVC to DetailVC to MyCartVC. Now, if user logged in the system I need to save him/her Cart with core data or etc.
i.e. User add a food to cart and log out him/her Cart must be saved when re-login.
I tried with UserDefaults self.myCartUserDefaults.set(myCartTableView.dataSource, forKey: "userCart") but it is not make sense.
I created CoreData entities for food name and price.
Here is MyCartVC
import UIKit
import CoreData
class MyCartViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var fromDetailFoodNames = ""
var fromDetailFoodPrices = ""
var backgroundView: UIView?
#IBOutlet weak var myCartTableView: UITableView!
#IBOutlet weak var totalPriceLabel: UILabel!
private let persistentContainer = NSPersistentContainer(name: "MyCartData")
var food: Food?
var fromSharedFood = SingletonCart.sharedFood.food
//TODO: - Approve my cart
#IBAction func approveCart(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.tabBar.isHidden = false
myCartTableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
self.myCartTableView.reloadData()
if foodCoreData.count == 0 {
myCartTableView.setEmptyView(title: "Sepetinizde ürün bulunmamaktadır", message: "Seçtiğiniz yemekler burada listelenir.")
}
else {
myCartTableView.restore()
self.tabBarController?.viewControllers![1].tabBarItem.badgeValue = "\(foodCoreData.count)"
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "MyCartData")
do {
foodCoreData = try managedContext.fetch(fetchRequest)
print("COREDATA FETCH EDİLDİ")
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if fromSharedFood.count != 0 {
tableView.restore()
}
return fromSharedFood.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foodName = fromSharedFood[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "myCartCell", for: indexPath) as! MyCartTableViewCell
cell.myCartFoodNameLabel.text = foodName.ProductTitle
self.tabBarController?.viewControllers![1].tabBarItem.badgeValue = "\(fromSharedFood.count)"
cell.myCartFoodPriceLabel.text = foodName.PriceString
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
fromSharedFood.remove(at: indexPath.row)
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .automatic)
if fromSharedFood.count == 0 {
myCartTableView.reloadData()
self.tabBarController?.viewControllers![1].tabBarItem.badgeValue = nil }
else {
self.tabBarController?.viewControllers![1].tabBarItem.badgeValue = "\(fromSharedFood.count)"
}
myCartTableView.restore()
}
tableView.endUpdates()
}
}
}
EDIT:
My data come from DetailVC with addBasket() button. First of all, I tried save DetailVC label datas to core data. After that fetched from MyCartVC but did not get any response.
Here is DetailVC:
import UIKit
import CoreData
class DetailViewController: UIViewController, TagListViewDelegate {
#IBOutlet weak var foodTitle: UILabel!
#IBOutlet weak var foodSubTitle: UILabel!
#IBOutlet weak var foodPrice: UILabel!
#IBOutlet weak var foodQuantity: UILabel!
#IBOutlet weak var detailFoodImage: UIImageView!
#IBOutlet weak var tagListView: TagListView!
var window: UIWindow?
var detailFoodName = ""
var detailFoodPrice = ""
var detailPhotoData = String()
var searchFoods: String!
var priceFood: Double!
var foodCoreData: [NSManagedObject] = []
var food: Food?
override func viewDidLoad() {
super.viewDidLoad()
foodQuantity.text = "1"
foodTitle.text = food?.ProductTitle ?? ""
foodPrice.text = food?.PriceString
foodSubTitle.text = food?.Description
tagListView.delegate = self
setupIngredientsTag()
self.tabBarController?.tabBar.isHidden = true
self.navigationController?.navigationItem.title = "Sipariş Detayı"
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "FoodOrder")
self.window?.rootViewController = viewController
}
func save(foodName: String, foodPrice: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "MyCartData",
in: managedContext)!
let foods = NSManagedObject(entity: entity,
insertInto: managedContext)
foods.setValue(foodName, forKeyPath: "fromDetailFoodNames")
foods.setValue(foodPrice, forKeyPath: "fromDetailFoodPrices")
do {
try managedContext.save()
foodCoreData.append(foods)
print("COREDATA KAYDEDİLDİ!")
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
//TODO:- Add to basket
#IBAction func addBasket(_ sender: Any) {
SingletonCart.sharedFood.food.append(food!)
self.performSegue(withIdentifier: "toMyCart", sender: nil)
self.navigationController?.navigationBar.isHidden = false
self.tabBarController?.tabBar.isHidden = false
self.isLoading(true)
guard let nameToSave = foodTitle.text else { return }
guard let priceToSave = foodPrice.text else { return }
self.save(foodName: nameToSave, foodPrice: priceToSave)
}
#IBAction func cancelButtonClicked(_ sender: UIBarButtonItem) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func favoriteButtonClicked(_ sender: UIBarButtonItem) {
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.isHidden = false
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.isHidden = true
}
}
SingletonCart
import Foundation
import UIKit
class SingletonCart {
static let sharedFood = SingletonCart()
var food: [Food] = []
private init() {}
}
Expected output is when user logout save him/her shopping cart.
You've got a couple of concepts wrong from what I see. Core Data Programming Guide will help you a lot to get how it works and how to save data.
For your table listings you should use an NSFetchedResultsController instead of managing a collection yourself.
Then when adding a new model from a detail View Controller you should create a new background context, create the entity, set its values and then save it.
appDelegate.persistentContainer.performBackgroundTask { (context) in
let entity =
NSEntityDescription.entity(forEntityName: "MyCartData",
in: managedContext)!
let foods = NSManagedObject(entity: entity,
insertInto: managedContext)
foods.setValue(foodName, forKeyPath: "fromDetailFoodNames")
foods.setValue(foodPrice, forKeyPath: "fromDetailFoodPrices")
_ = try? managedContext.save()
}
This will save this object to the persistent store, them refresh your view context and your NSFetchedResultsController will update your tableView controller automatically
Hello I have a tableviewcell where i can populate it with custom data from my pc, but i can't use my firebase data on the cell that i have made. I want to fill my cell with String and Int, not only Strings. My code is:
PlacesTableViewController Class
import UIKit
import FirebaseDatabase
class PlacesTableViewController: UITableViewController {
//MARK: Properties
#IBOutlet weak var placesTableView: UITableView!
//database reference
var dbRef:FIRDatabaseReference?
var places = [Places]()
var myList:[String] = []
//handler
var handle:FIRDatabaseHandle?
override func viewDidLoad() {
super.viewDidLoad()
dbRef = FIRDatabase.database().reference()
// Loads data to cell.
loadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return places.count
//return myList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "PlacesTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? PlacesTableViewCell else {
fatalError("The dequeued cell is not an instance of PlacesTableView Cell.")
}
let place = places[indexPath.row]
cell.placeLabel.text = place.name
cell.ratingControl.rating = place.rating
//cell.placeLabel.text = myList[indexPath.row]
//cell.ratingControl.rating = myRatings[indexPath.row]
return cell
}
//MARK: Private Methods
private func loadData() {
handle = dbRef?.child("placeLabel").observe(.childAdded, with: { (snapshot) in
if let item = snapshot.value as? String
{
self.myList.append(item)
self.placesTableView.reloadData()
print (item)
}
})
/* handle = dbRef?.child("rating").observe(.childAdded, with: { (snapshot) in
if let item = snapshot.value as? String
{
self.myList.append(item)
self.placesTableView.reloadData()
}
})*/
/*guard let place1 = Places(name: "Veranda", rating: 4) else {
fatalError("Unable to instantiate place1")
}
places += [place1]*/
}
}
Places Class
import UIKit
class Places {
//MARK: Properties
var name: String
var rating: Int
//MARK:Types
struct PropertyKey {
static let name = "name"
static let rating = "rating"
}
//MARK: Initialization
init?(name: String, rating: Int) {
// Initialize stored properties.
self.name = name
self.rating = rating
// Initialization should fail if there is no name or if the rating is negative.
// The name must not be empty
guard !name.isEmpty else {
return nil
}
// The rating must be between 0 and 5 inclusively
guard (rating >= 0) && (rating <= 5) else {
return nil
}
}
}
PlacesTableViewCell Class
import UIKit
import FirebaseDatabase
class PlacesTableViewCell: UITableViewCell, UITableViewDelegate {
//MARK: Properties
#IBOutlet weak var placeLabel: UILabel!
#IBOutlet weak var ratingControl: RatingControl!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Firebase Database
Assuming your database layout should instead look like this (see comments above):
...
placeLabel
|
-- XXY: "Veranda"
-- YYY: "Dio Con Dio"
rating
|
-- XXX: 4
-- YYY: 1
...
then try this:
private func loadData() {
dbRef!.child("placeLabel").observe(.childAdded) {
(snapshot) in
let label = snapshot.value as! String
self.updatePlace(snapshot.key, label: label)
}
dbRef!.child("rating").observe(.childAdded) {
(snapshot) in
let rating = snapshot.value as! Int
self.updatePlace(snapshot.key, rating: rating)
}
}
private var loadedLabels = [String: String]()
private var loadedRatings = [String: Int]()
private func updatePlace(_ key: String, label: String? = nil, rating: Int? = nil) {
if let label = label {
loadedLabels[key] = label
}
if let rating = rating {
loadedRatings[key] = rating
}
guard let label = loadedLabels[key], let rating = loadedRatings[key] else {
return
}
if let place = Places(name: label, rating: rating) {
places.append(place)
placesTableView.reloadData()
}
}
By the way, you can temporarily hack your database — using Firebase (nice!) web console — if you want to quickly validate the above solution.
Writing to Database. Try the following code to write the nodes in your database (i.e., this code reuses the same key across all place properties):
let key = dbRef!.child("placeLabel").childByAutoId().key
dbRef!.child("placeLabel").child(key).setValue(placeLabel.text)
dbRef!.child("comment").child(key).setValue(commentTextField.text)
dbRef!.child("rating").child(key).setValue(ratingControl.rating)
Hacking the Database. To edit the database manually, try:
open http://console.firebase.google.com
select your app
open database option
add a new node with the right key
delete the old node