Swift - Firebase Model - ios

I find myself stuck upon the implementation of a model for getting data from a firebase database.
I'm not sure what I've done so far is correct but as far as my knowledge of swift is concerned (I'm new to swift) I think I've followed the right path.
So I have a collection view which get the data from a firebase database.
The database structure is like so:
-SwimManager
--SwimmingPools
---SwimPoolName 1
-----Capacity: "2000"
-----PhotoUrl: "https//www.test"
---SwimPoolName 2
-----Capacity: "3000"
-----PhotoUrl: "https//www.test"
I'll show the code for the view controller, the model and the cell.
Here's my ViewController:
#IBOutlet weak var collectionView: UICollectionView!
var swimRef = Database.database().reference().child("SwimmingPools")
var swimmingPools = [SwimmingPool]()
verride func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
getSwimPoolInfo()
}
func getSwimPoolInfo() {
fishRef.observeSingleEvent(of: .value) { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let swimNameFb = snap.key
let value = snap.value
let swim = Fish(swimName: swimNameFb, photoUrl: "")
self.swimmingPools.append(swim)
// Not sure how to add the picture
}
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SwimCell", for: indexPath) as? SwimCell {
let swim: SwimminPool!
swim = swimmingPools[indexPath.row]
cell.configureCell(swim)
return cell
} else {
return UICollectionViewCell()
Model:
class SwimmingPool {
private var _swimName: String!
private var _photourl: String!
private var _capacity: String!
var swimName: String {
if _swimName == nil {
_swimName = ""
}
return _swimName
}
...............
init(swimName: String, photoUrl: String) {
self._SwimName = swimName
self._photourl = photoUrl
}
func getData() {
//perform action the get the data from the single swimmingPool (e.g. swimPoolName 1)
}
}
And finally, here's the cell:
class SwimCell: UICollectionViewCell {
#IBOutlet weak var swimThumb: UIImageView!
#IBOutlet weak var swimNameLbl: UILabel!
var swim: SwimmingPool!
func configureCell(_ swim: SwimmingPool) {
self.swim = swim
swimNameLbl.text = self.swim.swimName.capitalized
var url = URL(string: self.swim.photoUrl)
if url == nil {
url = URL(string: "")
}
swimThumb.sd_setImage(with: url)
}
}
In the Viewcontroller the func getSwimPooInfo is triggered after viewDidLoad and so the array swimminPools is empty... Honestly it seems I cannot figure where my mistake is....
Thx!

Related

Swift. Doesn't show data on my screen. iOS and Firebase

I faced such problem. When I launch the ios application, I get a white screen and the data that I take from Firebase is not displayed. How can i fix this problem? I would be grateful for your favorite recommendations for solving my problem
This is my ViewController
class ViewController: UIViewController {
#IBOutlet weak var cv: UICollectionView!
var channel = [Channel]()
override func viewDidLoad() {
super.viewDidLoad()
self.cv.delegate = self
self.cv.dataSource = self
let db = Firestore.firestore()
db.collection("content").getDocuments() {( quarySnapshot, err) in
if let err = err {
print("error")
} else {
for document in quarySnapshot!.documents {
if let name = document.data()["title"] as? Channel {
self.channel.append(name)
}
if let subtitle = document.data()["subtitle"] as? Channel {
self.channel.append(subtitle)
}
}
self.cv.reloadData()
}
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return channel.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ContentCell
let channel = channel[indexPath.row]
cell.setup(channel: channel)
return cell
}
}
This is my Model
struct Content {
let contents: [Channel]
}
struct Channel {
let title: String
let subtitle: String
}
This is my Cell
class ContentCell: UICollectionViewCell {
#IBOutlet weak var channelText: UILabel!
#IBOutlet weak var subtitle: UITextView!
func setup(channel: Channel) {
channelText.text = channel.title
subtitle.text = channel.subtitle
}
}
The data retrieved from Firestore can't just magically be cast to your custom type (Channel); it's a simple dictionary. You eighter need to use Codable or do it manually like so:
I can't tell how exactly to convert it as you have not shared the structure of your data in Firestore, but I assume this will work:
db.collection("content").getDocuments() { (snapshot, error) in
if let error = error {
print("error: \(error.localizedDescription)")
} else if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
if let title = data["title"] as? String,
let subtitle = data["subtitle"] as? String {
self.channel.append(Channel(title: title, subtitle: subtitle))
}
}
}
self.cv.reloadData()
}

Observe call from Firebase not updating value of dictionary after function exit

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.

Query Error while trying to populate data from Parse into CollectionView

So I am making an app, where the home view will show two sets of collection views. I am trying to filter how the information is sent and distributed into these two collectionviews based on a parameter from the image posted. My app is crashing down with this error.
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Below I'm putting all my code.
import UIKit
import Parse
class HomeViewController: UIViewController{
//VAR ARRAYS - LOST
var userslost = [String: String]()
var addresslost = [String]()
var breedlost = [String]()
var phonelost = [String]()
var usernameslost = [String]()
var imageFileslost = [PFFile]()
//VAR ARRAYS - FOUND
var usersfound = [String: String]()
var addressfound = [String]()
var breedfound = [String]()
var phonefound = [String]()
var usernamesfound = [String]()
var imageFilesfound = [PFFile]()
//#IBOUTLETS
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var lostView: UIView!
#IBOutlet weak var foundView: UIView!
#IBOutlet weak var lostCollectionView: UICollectionView!
#IBOutlet weak var foundCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
//QUERY LOST
let querylost = PFQuery(className: "Post")
querylost.whereKey("lostfound", equalTo: "lost")
querylost.findObjectsInBackground { (objects, error) in
if let posts = objects {
for post in posts {
self.addresslost.append(post["address"] as! String)
self.breedlost.append(post["breed"] as! String)
self.usernameslost.append(self.userslost[post["userid"] as! String]!)
self.imageFileslost.append(post["imageFile"] as! PFFile)
}
}
}
// QUERY FOUND
let queryfound = PFQuery(className: "Post")
queryfound.whereKey("lostfound", equalTo: "found")
queryfound.findObjectsInBackground { (objects, error) in
if let posts = objects {
for post in posts {
self.addressfound.append(post["address"] as! String)
self.breedfound.append(post["breed"] as! String)
self.usernamesfound.append(self.userslost[post["userid"] as! String]!) **--> ERROR IS HERE**
self.imageFilesfound.append(post["imageFile"] as! PFFile)
}
}
}
//TO SHOW DATA
scrollView.delegate = self
lostCollectionView.delegate = self
lostCollectionView.dataSource = self
foundCollectionView.delegate = self
foundCollectionView.dataSource = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// START OF EXTENSIONS FOR COLLECTION VIEWS
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.lostCollectionView {
return addresslost.count
//DUDA #2
}
else {
return addressfound.count
//DUDA #2
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.lostCollectionView {
let cell: LostCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "Lostcell", for: indexPath) as! LostCollectionViewCell
//TIENES QUE IGUALAR LOS #IBOUTLETS DEL CELL (SPECIFICOS A LOST) Y IGUALARLOS CON EL ARRAY DE PARSE QUE PUEDES ENCONTRAR EN VARS ARRIBA
cell.adressLostLabel.text = addresslost[indexPath.row]
cell.breedLostLabel.text = breedlost[indexPath.row]
cell.phoneLostLabel.text = phonelost[indexPath.row]
imageFileslost[indexPath.row].getDataInBackground { (data, error) in
if let imageData = data {
if let imageToDisplay = UIImage(data: imageData) {
cell.postedImage.image = imageToDisplay
}
}
}
return cell
}
else {
let cell: FoundCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "Foundcell", for: indexPath) as! FoundCollectionViewCell
cell.adressFoundLabel.text = addressfound[indexPath.row]
cell.breedFoundLabel.text = breedfound[indexPath.row]
cell.phoneFoundLabel.text = phonefound[indexPath.row]
imageFilesfound[indexPath.row].getDataInBackground { (data, error) in
if let imageData = data {
if let imageToDisplay = UIImage(data: imageData) {
cell.postedImage.image = imageToDisplay
}
}
}
return cell
}
}
}
//SCROLL
extension HomeViewController: UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView)
}
}
Error can be found in this line of code:
self.usernamesfound.append(self.userslost[post["userid"] as! String]!)
Please insert this in, it should work:
self.usernamesfound.append(self.userslost[post["userid"] as? String]?)

Table view cell information resetting when scrolling

I am currently using a table view to display a menu, in which people can click on the add or subtract buttons to increase/decrease their order.
This table view has approximately 30 items and so you have to scroll down to get to all the menu items. The problem is, when you scroll down, the table view cells above the scroll (that are now hidden) lose the data that they have just contained.
For example, if you have a menu item that you have ordered 2 of an item, that 2 on the label has now turned back to 0. This is very object oriented so I am not sure why this is happening.
My table view class:
#IBOutlet weak var appetizerTableView: UITableView!
var appetizerList = [OrderModel]()
let ref = FIRDatabase.database().reference()
override func viewDidLoad() {
appetizerTableView.delegate = self
appetizerTableView.dataSource = self
ref.child("Broadway").child("AppetizerDishes").observeSingleEventOfType(.Value, withBlock: { snapshot in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print("WILL: \(snap)")
if let postDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let post = OrderModel(postkey: key, postData: postDict)
self.appetizerList.append(post)
}
}
}
self.appetizerTableView.reloadData()
})
}
var data=[OrderModel]()
func addButtonAction(addedList:[String:Float]) {
print("WILLCOHEN:\(addedList)")
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return appetizerList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = appetizerList[indexPath.row]
if let cell = appetizerTableView.dequeueReusableCellWithIdentifier("OrderCell") as? OrderCell{
cell.configureCell(post)
cell.delegate = self
return cell
} else {
return OrderCell()
}
}
}
My cell model class:
class OrderModel {
private var _dishName: String!
private var _dishDescription: String!
private var _numberOfOrders: Int!
private var _postKey: String!
private var _dishPrice: Float!
var dishName: String {
return _dishName
}
var dishDescription: String {
return _dishDescription
}
var numberOfOrders: Int {
get {
return _numberOfOrders
}
set (newVal) {
_numberOfOrders = newVal
}
}
var postKey: String {
return _postKey
}
var dishPrice: Float {
return _dishPrice
}
init(dishName: String, dishDescription: String, numberOfOrders: Int) {
self._dishName = dishName
self._dishDescription = dishDescription
}
init(postkey: String, postData: Dictionary<String, AnyObject>) {
self._postKey = postkey
if let dishName = postData["dishName"] as? String {
self._dishName = dishName
}
if let dishDescription = postData["dishDescription"] as? String {
self._dishDescription = dishDescription
}
if let numberOfOrders = postData["anumberOfOrders"] as? Int {
self._numberOfOrders = numberOfOrders
}
if let dishPrice = postData["dishPrice"] as? Float32 {
self._dishPrice = dishPrice
}
}
}
My cell class:
protocol ClassNameDelegate:class {
func addButtonAction(addedList:[String:Float])
}
var addedList: [String:Float] = [:]
class OrderCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
var post: OrderModel!
var link: Link!
#IBOutlet weak var dishName: UILabel!
#IBOutlet weak var dishDescriptionAndPrice: UILabel!
#IBOutlet weak var numberOfOrders: UILabel!
#IBOutlet weak var addOrderBtn: UIButton!
#IBOutlet weak var subtractOderBtn: UIButton!
weak var delegate: ClassNameDelegate?
#IBAction func addButtonPressed(sender: AnyObject) {
if post.numberOfOrders == 9 {
numberOfOrders.text = "9"
} else {
if addedList[post.dishName] != nil {
addedList[post.dishName] = post.dishPrice
} else {
addedList["\(post.dishName) \(Int(numberOfOrders.text!)! + 1)"] = post.dishPrice
}
post.numberOfOrders = post.numberOfOrders - 1
numberOfOrders.text = "\(post.numberOfOrders)"
}
if delegate != nil {
delegate?.addButtonAction(addedList)
}
}
#IBAction func subtractButtonPressed(sender: AnyObject) {
if post.numberOfOrders == 0 {
numberOfOrders.text = "0"
} else {
post.numberOfOrders = post.numberOfOrders + 1
numberOfOrders.text = "\(post.numberOfOrders)"
}
}
func getOrders() -> Dictionary<String, Float> {
return addedList
}
func configureCell(post: OrderModel) {
self.post = post
self.dishName.text = post.dishName
self.dishDescriptionAndPrice.text = post.dishDescription
self.numberOfOrders.text = "0"
}
}
I should mention that I am pulling my table view data from Firebase.
Thank you in advance for any help or suggestions, it is very much appreciated.
You are calling configureCell(post:) on every cell, and in the configureCell(post:) function you set the text value of the numbersOfOrders label to "0". You should probably set the text to a value in the OrderModel/post argument.
Also, you should be sure to always call configureCell(post:) (you are not calling it if you have to manually create an OrderCell), so your tableView(tableView:cellForRowAtIndexPath:) function should look like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = appetizerList[indexPath.row]
let cell = appetizerTableView.dequeueReusableCellWithIdentifier("OrderCell") as? OrderCell ?? OrderCell()
cell.configureCell(post)
cell.delegate = self
return cell
}

How to display data in Firebase that is held under a autoID child?

I am creating an inventory app in order to keep track of items held in a laboratory. In the laboratory there are different stations which contain different items in them, which as you can see is structured properly in my Firebase database.
Firebase Database
Iphone Simulator
My problem comes when I try to delete a particular item out of the tableCell. I am able to remove it from the UI but in firebase the data still remains. I have done coutless reserch but am not able to find anything relating to this particular problem.
Data Services Class
let DB_BASE = FIRDatabase.database().reference().child("laboratory") //contains the root of our database
let STORAGE_BASE = FIRStorage.storage().reference()
class DataService {
static let ds = DataService()
//DB References
private var _REF_BASE = DB_BASE
private var _REF_STATION = DB_BASE.child("stations")
private var _REF_USERS = DB_BASE.child("users")
//Storage Reference
private var _REF_ITEM_IMAGE = STORAGE_BASE.child("item-pics")
var REF_BASE: FIRDatabaseReference {
return _REF_BASE
}
var REF_STATION: FIRDatabaseReference {
return _REF_STATION
}
var REF_USERS: FIRDatabaseReference {
return _REF_USERS
}
var REF_ITEM_IMAGES: FIRStorageReference {
return _REF_ITEM_IMAGE
}
//creating a new user into the firebase database
func createFirebaseDBUser(_ uid: String, userData: Dictionary<String, String>) {
REF_USERS.child(uid).updateChildValues(userData)
}
}
Inventory View Controller
import UIKit
import Firebase
class InventoryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var items = [Item]()
private var _station: Station!
private var _item: Item!
var sortIndex = 3
var imagePicker: UIImagePickerController!
static var imageCache: NSCache<NSString, UIImage> = NSCache()
var imageSelected = false
#IBOutlet weak var itemImageToAdd: UIImageView!
#IBOutlet weak var objectTextInput: UITextField!
#IBOutlet weak var brandTextInput: UITextField!
#IBOutlet weak var unitTextInput: UITextField!
#IBOutlet weak var amountTextInput: UITextField!
#IBOutlet weak var tableView: UITableView!
#IBOutlet var addItemView: UIView!
#IBOutlet weak var currentStationLabel: UILabel!
var station: Station {
get {
return _station
} set {
_station = newValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
var currentStationName = station.title
currentStationLabel.text = currentStationName
self.items = []
let currentStation = station.title
let stationRef = DataService.ds.REF_STATION.child(currentStation!)
let inventoryRef = stationRef.child("inventory")
tableView.delegate = self
tableView.dataSource = self
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = true
imagePicker.delegate = self
inventoryRef.observe(.value, with: { (snapshot) in
print(snapshot.value!)
self.items = []
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print("SNAP: \(snap)")
if let itemDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let item = Item(itemKey: key,
itemData: itemDict)
self.items.append(item)
}
}
}
self.tableView.reloadData()
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "inventoryTableCell", for: indexPath) as? ItemCell {
if let img = InventoryViewController.imageCache.object(forKey: NSString(string: item.imageURL!)) {
cell.updateItemUI(item: item, img: img)
} else {
cell.updateItemUI(item: item)
}
return cell
} else {
return ItemCell()
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func postToFirebase(itemImageURL: String) {
let post: Dictionary<String, AnyObject> = [
"objectLabel": objectTextInput.text! as AnyObject,
"brandLabel": brandTextInput.text! as AnyObject,
"unitLabel": unitTextInput.text! as AnyObject,
"amountLabel": amountTextInput.text! as AnyObject,
//post elsewhere as an image for future reference
"itemImageURL": itemImageURL as AnyObject,
]
let stationText = _station.title
let stationRef = DataService.ds.REF_STATION.child(stationText!)
let inventoryRef = stationRef.child("inventory")
let firebasePost = inventoryRef.childByAutoId()
firebasePost.setValue(post)
objectTextInput.text = ""
brandTextInput.text = ""
unitTextInput.text = ""
amountTextInput.text = ""
imageSelected = false
tableView.reloadData()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
itemImageToAdd.image = image
imageSelected = true
} else {
print("Please select a valid image")
}
imagePicker.dismiss(animated: true, completion: nil)
}
#IBAction func backToStations(_ sender: Any) {
performSegue(withIdentifier: "backToStations", sender: nil)
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(tableView: (UITableView!), commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: (NSIndexPath!)) {
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let currentStation = station.title
let stationRef = DataService.ds.REF_STATION.child(currentStation!)
let inventoryRef = stationRef.child("inventory")
var deleteAction = UITableViewRowAction(style: .default, title: "Delete") {action in
//Insert code to delete values from Firebase
self.items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath as IndexPath], with: .fade)
}
var editAction = UITableViewRowAction(style: .normal, title: "Edit") { action in
}
return [deleteAction, editAction]
}
}
My thought process is upon delete to call self_items.key reffering to the current key of the particular tableCell row. From there I would use the current key whick would be the autoID and remove the value that way. Unfortunatly though that crashes the program with a fatal nil error.
The best way I've found to solve this problem is in your delete action, delete the object from Firebase. Do not alter the tableview from here.
Then in your data listener, check when the data comes back as deleted(or NULL), then remove it from the tableview datasource array and update the tableview.

Resources