How do you display 2 tableViews of the same user? Firebase database - firebase

Firebase Database
driver1 Main page
toyota car details
FInal Output
So the problem is that driver1 has 2 cars. how can i make the tableView show for toyota car information and mazda car information.
I was able to show driver 1's car list by this code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "driverRequestCell", for: indexPath)
if let email = Auth.auth().currentUser?.email {
Database.database().reference().child("Driver").queryOrdered(byChild: "email").queryEqual(toValue: email).observe(.childAdded, with: { (snapshot) in
let snapshot = self.driverRequests[indexPath.row]
if let driverRequestDictionary = snapshot.value as? [String:AnyObject] {
if let typeOfCar = driverRequestDictionary["car"] as? String {
cell.textLabel?.text = typeOfCar
}
}
})
}
return cell
}
So my current code for didSelectRowAt is:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let snapshot = driverRequests[indexPath.row]
performSegue(withIdentifier: "carDetailsSegue", sender: snapshot)
}
I think it has something to do with the snapshot, but I can't figure it out. Need help from the pro's

If you want to show all car information in the same cell, first you need a cell with three UILabel, one for all of the information you want to show, This is an example:
I suppose you have your own custom cell class, so you need to drag&drop label outlets into your class.
Now, you have to change you code into cellForRowAt: this way:
if let driverRequestDictionary = snapshot.value as? [String:AnyObject] {
if let typeOfCar = driverRequestDictionary["car"] as? String {
cell.modelLabel?.text = typeOfCar
}
if let colorOfCar = driverRequestDictionary["color"] as? String {
cell.colorLabel?.text = colorOfCar
}
if let plateOfCar = driverRequestDictionary["plate"] as? String {
cell.plateLabel?.text = plateOfCar
}
}
You can use a default value if color and plate doesn't exists adding else statements, or using three operand:
`if let plateOfCar = driverRequestDictionary["plate"] as? String {
cell.plateLabel?.text = plateOfCar
}else{
cell.plateLabel?.text = "Unknown"
}`
ADVICE: Avoid to do a request into cellForRowAt:, Instead of this, make an asynchronous request (on viewDidLoad: for example) using a closure. Then use the result of the closure to fill an array and then reload you table view.
EDIT:
You should struct your nodes this way, where giuseppesapienza is user ID, while note is your car objext:

Related

Wrong cell data if fast scroll CollectionView swift 5

Can anybody help me with CollectionView? I parce JSON from some API, and get String values - title and image adress, then assign that Data to custom collectionViewCell in method cellForItem(). BUT than i fast scroll the collection view some cell can be with wrong images, or duplicate images. I also override method prepareForReuse in my custom cell class and set cell.image = UIImage() , but it didnt work. Please help me to understand what wrong)
Sorry for my poor English...
collectionViewController
'''
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Result",
for: indexPath) as! ResultCell
let film = results[indexPath.item]
cell.name.text = film.title
cell.imageView.layer.borderColor = UIColor(white: 0, alpha: 0.3).cgColor
cell.imageView.layer.borderWidth = 2
cell.imageView.layer.cornerRadius = 10
cell.layer.cornerRadius = 10
// setUp image for cell
cell.imageView.image = nil
contentManager.getImage(film.poster.image, cell.imageView)
return cell
}
'''
method get image
'''
func getImage(_ url_str:String, _ imageView:UIImageView) {
let url:URL = URL(string: url_str)!
let session = URLSession.shared
let task = session.dataTask(with: url, completionHandler: {(data, response, error) in
if data != nil {
let image = UIImage(data: data!)
if(image != nil) {
DispatchQueue.main.async(execute: {
imageView.image = image
imageView.alpha = 0
UIView.animate(withDuration: 1, animations: {
imageView.alpha = 1.0
})
})
}
}
})
task.resume()
}
'''
Cell custom class
'''
class ResultCell: UICollectionViewCell {
#IBOutlet var imageView: UIImageView!
#IBOutlet var name : UILabel!
override func prepareForReuse() {
self.imageView.image = UIImage()
self.name.text = nil
super.prepareForReuse()
}
}
'''

Reorder and Move NSTableView Row with NSPasteboard

I have an NSTableView where I can drag and drop table rows to reorder them. This works by setting a drag type in my view controller:
#IBOutlet weak var tableView: NSTableView!
let dragType = NSPasteboard.PasteboardType(rawValue: "myapp.task")
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerForDraggedTypes([dragType])
}
...and then implementing the reordering with these table delegate methods:
//Start drag
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let item = NSPasteboardItem()
item.setString(String(row), forType: dragType)
return item
}
//Verify proposed drop
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
}else{
return []
}
}
//Accept drop of one or multiple rows
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) { dragItem, _, _ in
if let str = (dragItem.item as! NSPasteboardItem).string(forType: self.dragType), let index = Int(str) {
oldIndexes.append(index)
}
}
//Do a bunch of logic to reorder the table rows...
}
Now, in addition to reordering my table rows, I want to be able to drag a row and drop it somewhere else in my app--sort of like moving the row to a different place.
I have a custom NSView set up as the drag destination for this, and I can drag a table row and the custom view reacts appropriately with a table row dragged over it:
class MyCustomView: NSView{
required init?(coder: NSCoder) {
super.init(coder: coder)
let taskDragType = NSPasteboard.PasteboardType(rawValue: "myapp.task")
registerForDraggedTypes([taskDragType])
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
//...
}
override func draggingExited(_ sender: NSDraggingInfo?) {
//...
}
}
But the part I'm unclear on is how to get the table row, and its associated object set as a property on the NSTableCellView, when the drop occurs:
//This is another method in MyCustomView
override func performDragOperation(_ draggingInfo: NSDraggingInfo) -> Bool {
guard let items = draggingInfo.draggingPasteboard.pasteboardItems else{ return false }
for item in items{
print("---")
print(item) //<-- NSPasteboardItem
let index = item.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "myapp.task"))
print(index) //<-- Index of the table row
//How can I also get the task object associated with the row?
}
}
I can get the index of the row, but what I need is the entire object from the row's data source so I can take action on the object it represents. My suspicion is that I need to change how I'm using pasteboardWriterForRow to put my object on the pasteboard, but I'm unsure how to do that.
How can I pass both the row index and the object to the pasteboard?
Soon after posting this, I decided to try something crazy, and it turns out I found a way to make this a lot simpler. It seems that NSPasteboard is really only necessary if you need to get stuff into and out of your app. Since I am just moving something from one part of my app to another, I can use the drag and drop delegate methods as events and handle the data myself.
First, I set up a global array for adding dragged task objects:
var draggedTasks = [Task]()
Whenever a task is dragged from my NSTableView, I add them to the array in the aforementioned delegate method where dragging starts:
//Start drag
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
//Queue tasks for moving to phases or projects
draggedTasks.append(tasks[row])
//Queue row for reordering
let item = NSPasteboardItem()
item.setString(String(row), forType: dragType)
return item
}
Then where I accept the drop in MyCustomView, I take action on the draggedTasks array:
//Save dropped tasks
override func performDragOperation(_ draggingInfo: NSDraggingInfo) -> Bool {
//Do stuff to draggedTasks based on the context of where they are dropped
return true
}
This is much simpler than going down the NSPasteboard route. 🙂

String with line breaks "\n" used for UILabel inside UITableViewCell not breaking

Can't get the String to break into lines. I'm passing the data from MainViewController to be displayed in a single row table. I've tried passing the object product with a class of Product therefore getting the product description as product.description. I've also tried just passing the String instead but either way I get the result shown in the images. The descriptions comes from a Firestore database stored as for example: string Available In Black And White\nOne Piece Swimsuit\nScoop Neck\nCheeky Coverage\nStrappy Detail At Back\n90% Nylon 10% Spandex\nFinal Sale
I've tried several ways:
var product: Product?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "description", for: indexPath) as! ProductDescriptionTableViewCell
cell.descriptionLabel.text = product?.description
return cell
}
or loading the description in viewDidLoad()
var product: Product?
var productDescription = String()
override func viewDidLoad() {
super.viewDidLoad()
productDescription = product!.description
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "description", for: indexPath) as! ProductDescriptionTableViewCell
cell.descriptionLabel.text = productDescription
return cell
}
I still can't get the desired outcome of the String breaking using "\n". I tested it and it works adding the text directly using:
cell.descriptionLabel.text = "Available In Black And White\nOne Piece Swimsuit\nScoop Neck\nCheeky Coverage\nStrappy Detail At Back\n90% Nylon 10% Spandex\nFinal Sale"
so I know that the cell's height and the label's number of lines work.

NSUnknownKeyException on a model variable

'[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key text.'
I'm getting an NSUnknownKeyException at the text variable of my Message model when I attempt to access it in my second tableView() function (at the end of this code). I am still pretty new to swift and don't know how to resolve this. Through my google searches, I found that it could be something to do with storyboards, but I've actually opted to create my UI programmatically so I'm not sure how that could be causing this.
import UIKit
import Firebase
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "chat", style: .plain, target: self, action: #selector(handleChat))
observeMessages()
}
#objc func handleChat() {
let chatController = ChatController(collectionViewLayout: UICollectionViewLayout())
navigationController?.pushViewController(chatController, animated: true)
//present(chatController, animated: true, completion: nil)
}
var messages = [Message]()
func observeMessages() {
let ref = Database.database().reference().child("FalconsVPackers").child("messages")
ref.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let message = Message()
message.setValuesForKeys(dictionary)
self.messages.append(message)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "called")
let message = messages[indexPath.row]
cell.textLabel?.text = message.text
return cell
}
}
My Message model is very simple...
import UIKit
class Message: NSObject {
var text: String?
}
Any help or advice would be greatly appreciated!
You are using NSKeyValueCoding to populate Message object so you must add #objc to text property.
message.setValuesForKeys(dictionary) // NSKeyValueCoding
.
class Message : NSObject {
#objc var text: String?
}
If you just want to populate your message object, better just use properties directly instead of setValuesForKeys. And in this case you don't have to use #objc too.
let message = Message()
message.text = dictionary["text"]

Select a Row in a tableView after fetching CoreData to pass the result to sender View Controller

I have been struggling with this issue for a long time being a novice in Swift iOs coding. Hope that someone can point me to the right direction.
In the following code I do a Fetchrequest to a CoreData Entity with names of persons. Once I get the results I am trying to pick (tapping on the corresponding row) one name and pass it back to the ViewController that invoked this view with a prepare for segue.
But each time I click on the row of the name I want to select, I end up with a: "*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.'"
It seems I am invoking my indexPath in the wrong way.
Here below my code:
.....
.....
let fetchedResults =
managedObjectContext.executeFetchRequest(fetchRequest,
error: &error) as [NSManagedObject]?
if let results = fetchedResults {
names = results
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}
// MARK: - UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("KidCell") as UITableViewCell
let kidName = names[indexPath.row]
cell.textLabel!.text = kidName.valueForKey("kidName") as String?
if kidName != selectedKid {
cell.accessoryType = .None
} else {
cell.accessoryType = .Checkmark
selectedIndexPath = indexPath
}
return cell
}
// MARK: - UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row != selectedIndexPath.row {
if let newCell = tableView.cellForRowAtIndexPath(indexPath) {
newCell.accessoryType = .Checkmark
}
if let oldCell = tableView.cellForRowAtIndexPath(selectedIndexPath) {
oldCell.accessoryType = .None
}
selectedIndexPath = indexPath
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SelectedKid" {
let cell = sender as UITableViewCell
if let indexPath = tableView.indexPathForCell(cell) {
let kidName = names[indexPath.row]
selectedKid = kidName.valueForKey("kid") as String!
}
}
}
}
The idea is that when I tap on the name I go back with an unwind segue to the sender controller and I put the selectedName in the correct place.
Thank you fro any help!
Cristiano
your problem are with the lines below...
let cell = tableView.dequeueReusableCellWithIdentifier("KidCell") as UITableViewCell
let kidName = names[indexPath.row]
cell.textLabel!.text = kidName.valueForKey("kidName") as String?
your code should look like...
let cell = tableView.dequeueReusableCellWithIdentifier("KidCell", forIndexPath: indexPath ) as UITableViewCell
let kidName = names[indexPath.row]
cell.textLabel!.text = kidName.valueForKey(kidName)

Resources