Using Array of Dictionary to populate tableview in Swift - ios

I have an array of dictionary created as below:
var menuItems = [["Image" : "bars_icon_main_page", "Title" : "Bars"], ["Image" : "clubs_icon_main_page", "Title" : "Clubs"]]
I've created a custom table view cell and populating the table view cell as below:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: MenuTableViewCell = tableView.dequeueReusableCellWithIdentifier("MenuCell") as MenuTableViewCell
let dict = menuItems[indexPath.row]
cell.menuImage.image = UIImage(named: dict["Image"]!)
cell.menuTitle.text = dict["Title"]
return cell
}
When debugging the src code, after executing below line, "dict" is nil.
let dict = menuItems[indexPath.row]
I am not able to make out what's the issue.

The following line of code is looking for a key of Image:
cell.menuImage.image = UIImage(named: dict["Image"]!)
But menuItems is using Image: as the key:
var menuItems = [["Image:" : "bars_icon_main_page", "Title" : "Bars"], ["Image:" : "clubs_icon_main_page", "Title" : "Clubs"]]
I suspect you did not intend to include the colon in the key:
var menuItems = [["Image" : "bars_icon_main_page", "Title" : "Bars"], ["Image" : "clubs_icon_main_page", "Title" : "Clubs"]]

Your array of Dictionary is implementing with Image: key and your code is using Image without : in key

Related

Swift 4 Implementing drag & drop in collectionView with Cells

I have custom classes which create an array of objects that are then turned into cells dynamically for my UICollectionView, and the classes all essentially look like this:
import Foundation
class BoardNote : NSObject {
var note_id : String = ""
var itemType : String = ""
var added_by : Any = ""
var link : Any = ""
var content : String = ""
var board_id : Any = ""
var date_added : Any = ""
}
An instance of this class is then used to create a cell like so:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"noteViewCell", for: indexPath) as! NoteViewCell
cell.content.text = (itemArray[indexPath.row] as!
BoardNote).content
cell.noteId = (itemArray[indexPath.row] as! BoardNote).note_id
print("made note cell")
return cell
When I try to implement basic drag & drop in my collection view, I get the error "Could not cast value of type "BoardNote" to 'NSObject'.
I see that I might need to also make this an extension of class NSItemProviderWriting but I am not sure how.
Here is the beginning of my DragDelegate extension where the error is occurring on line 4, which is a Thread 1: signal SIGABRT:
extension BoardViewController : UICollectionViewDragDelegate
{
func collectionView(_ collectionView: UICollectionView,
itemsForBeginning session: UIDragSession, at indexPath: IndexPath) ->
[UIDragItem]
{
let item = self.itemArray[indexPath.row]
let itemProvider = NSItemProvider(object: item as! NSObject as!
NSItemProviderWriting)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
Thanks!
First, you need to delete the item cast on this line:
NSItemProvider(object: item as! NSObject as! NSItemProviderWriting)
Make it just:
NSItemProvider(object: item)
Then, the error is self-explained: You need to make you custom class to conform NSItemProviderWriting and NSItemProviderReading protocol, then add the stub methods required from the protocols:
class BoardNote : NSItemProviderWriting, NSItemProviderReading{
var note_id : String = ""
var itemType : String = ""
var added_by : Any = ""
var link : Any = ""
var content : String = ""
var board_id : Any = ""
var date_added : Any = ""
}
NOTE: you can omit NSObject inheritance, here is why
You can add protocol stubs simply by clicking on error red signal then clicking "Fix".
Here a tutorial on how to do Drag and Drop, so you can check how to fill NSItemProviderWriting and NSItemProviderReading protocol stubs.
Here a similar question you can check
Basically, the question I linked was asking for a problem in your same line NSItemProvider(object: item), but the problem was the dev was not giving the method a class instance but the class name

swift table view cells does not let me use indexPath.row

i am trying to populate data into cells inside of a table view. I created a chosenPlanData var which is initialized to an object with the data inside of it.. The object has properties such as "name" and "event location". An issue occurs when inside of 'cellForRowAt'. It does not let me add [indexPath.row] to the cell i am creating, which in turn does not populate the cells correctly.
For instance - i removed indexPath.row from the first cell.nameLbl.text call - and in turn every single name label in the table view was the same. here is piece of the code
var chosenPlanData = ChosenPlan()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "individualPlansCell") as? PlanitsHomeViewCell else { return UITableViewCell() }
cell.nameLbl.text = chosenPlanData.nameOfEvent[indexPath.row] // error Cannot assign value of type 'Character' to type 'String?'
cell.dateAndTimeLbl.text = chosenPlanData.eventStartsAt[indexPath.row] as? String // error 'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion
cell.nameLbl.text = chosenPlanData.nameOfEvent // This works - but every single cell has the same nameLbl though
return cell
}
// Here is the call back where i initialize the value for chosenPlanData
let EventbriteTVC = segue.destination as! EventbriteTableView
EventbriteTVC.callbackChosePlan = { result in
DispatchQueue.main.async {
self.individualPlanitsTableView.reloadData()
}
self.chosenPlanData = result
}
import Foundation
import UIKit
class ChosenPlan {
var nameOfEvent : String = ""
var eventStartsAt : String = ""
var eventLocationIs : String = ""
var eventURL : String = ""
var imageForPlan : String?
convenience init( eventName: String, eventTime: String, eventLocation: String, eventImage: String){
self.init()
self.nameOfEvent = eventName
self.eventStartsAt = eventTime
self.eventLocationIs = eventLocation
//self.eventURL = eventLink
self.imageForPlan = eventImage
//eventLink: String,
}
}
Your chosenPlanData variable is a single instance of ChosenPlan - You cannot subscript a single instance.
It needs to be an array of ChosenPlan:
var chosenPlanData = [ChosenPlan]()
Then you can index into this array:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "individualPlansCell") as? PlanitsHomeViewCell else { return UITableViewCell() }
cell.nameLbl.text = chosenPlanData[indexPath.row].nameOfEvent
cell.dateAndTimeLbl.text = chosenPlanData[indexPath.row].eventStartsAt
extending my comment
var chosenPlanData = ChosenPlan()
chosenPlanData is object of ChosenPlan
Now in cellForRow you writing chosenPlanData.nameOfEvent[indexPath.row] but nameOfEvent is String as per your ChosenPlan that you mentioned in question.
For more info,
chosenPlanData.nameOfEvent[indexPath.row] this line represents you using the n th (indexPath.row) object of nameOfEvent which is object of chosenPlanData
Hope now will be more cleared.
Solution
var chosenPlanData = [ChosenPlan]() <- create array
In cellForRow chosenPlanData[indexPath.row].nameOfEvent that means you'r using nameOfEvent of nth object of chosenPlanData.
Type handling is very important in Swift. Try this.
cell.nameLbl.text = String(chosenPlanData.nameOfEvent[indexPath.row])
let index = chosenPlanData.eventStartsAt.index(chosenPlanData.eventStartsAt.startIndex, offsetBy: 3)
cell.dateAndTimeLbl.text = String(chosenPlanData.eventStartsAt[index])
if
var chosenPlanData = [ChosenPlan]()
Try this:-
cell.nameLbl.text = "\(chosenPlanData[indexPath.row].nameOfEvent)"
or
cell.nameLbl.text = "\(chosenPlanData[indexPath.row].nameOfEvent ?? "")"

how to pass dictionary with key to table view

import UIKit
import Firebase
class PendingVC: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
let ref = firebasehelper.firebaseURL()
var data = [[:]]
//MARK: vars
var address:AnyObject!
var postTitle:AnyObject!
override func viewDidLoad() {
super.viewDidLoad()
myTableView.dataSource = self
myTableView.delegate = self
//The example below work great I get the layout the way it should look, but i want to generate the dictionary from the firebase function below.
/*
self.data = [
[
"firstname": "sallie",
"lastname": "ammy"
],
[
"firstname": "jamie",
"lastname": "brown"
]
]
*/
It should look something like this and i want to past the data to the table. Im not sure if i should be looping. the way it is below bring the following error "fatal error: unexpectedly found nil while unwrapping an Optional value" the variables are not nil when i print them i get data back.
ref.childByAppendingPath("backend/posts").queryOrderedByChild("requestFrom").queryEqualToValue(ref.authData.uid).observeEventType(.ChildAdded, withBlock: {snapshot in
var firstname = snapshot.value["firstname"] as! String
var lastname = snapshot.value["lastname"] as! String
self.data = [
[
"firstname": firstname,
"lastname": lastname
]
]
print(self.data)
})
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! statusPrototypeCell
let object = data[indexPath.row]
cell.firstname.text = object["firstname"] as! String
cell.lastname.text = object["lastname"] as! String
return cell
}
override func viewWillAppear(animated: Bool) {
navigationController?.navigationBarHidden = false
navigationController?.navigationBar.barTintColor = UIColor(red:0.4, green:0.76, blue:0.93, alpha:1.0)
navigationController?.navigationBar.translucent = false
self.title = "Signup"
self.navigationController?.navigationBar.tintColor = UIColor.whiteColor()
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
}
}
While you can use a dictionary as a dataSource, it's unordered which means the items in your tableView will also be unordered. Using an array is a better solution. In fact, an array of dictionaries make a nice ordered data source.
Also, to clarify, you don't pass a dictionary or data to a tableView per your question. The tableView gathers it's data from a datasource via it's delegate methods
Assume the following Firebase data structure
"users" : {
"uid_0" : {
"first_name" : "Bill",
"last_name" : "Nye"
},
"uid_1" : {
"first_name" : "Leroy",
"last_name" : "Jenkins"
},
"uid_2" : {
"first_name" : "Peter",
"last_name" : "Sellers"
}
}
and to populate an array of dictionaries:
var usersArray: [Dictionary<String, String>] = []
let usersRef = self.myRootRef.childByAppendingPath("users")
usersRef.observeEventType(.ChildAdded, withBlock: { snapshot in
var userDict = [String:String]()
userDict["key"] = snapshot.key
userDict["firstName"] = snapshot.value["first_name"] as? String
userDict["lastName"] = snapshot.value["last_name"] as? String
self.usersArray.append(userDict)
})
to access the data, use the keys you created above.
For example: to print the users in the array from a button
for userDict in self.usersArray {
let key = userDict["key"]
let fName = userDict["firstName"]
let lName = userDict["lastName"]
print("\(key!) \(fName!) \(lName!)")
}
Once you have an understanding of that, you can then use the usersArray to populate the tableView.
let userDict = usersArray[indexPath.row]
cell.firstname.text = userDict["firstName"] as! String
cell.lastname.text = userDict["lastName"] as! String
The tricky bit is loading the array with all of the data needed, then reload the tableView to display it. If you have a small set of data, .Value will work for that. A larger set of data requires another technique, see This Answer
You are using Dictionary so it doesn't returning count value so better to use array like [] instead of [:]
One more thing You have forgot the following statement to include in ViewDidLoad method
myTableView.delegate = self

Accessing data in filtered array

I am implementing UISearchBar and I using filtered array where will be collected matching results. My problem is in TableView I do not know what is the proper way accessing items in "menuItemsFiltered" array. My goal is when searching for a title to display correct Image that assigned to that title. Please help!
//Declaring dict arrays:
var menuItems = [["Name" : "20/20 Cafe", "Image": "20_20Cafe.jpg"],
["Name": "Au Bon Pain", "Image": "AuBonPain.jpg"]]
var menuItemsFiltered = [(Name:String, Image:UIImage)]()
Here is my TableView
//Display info in our Residential cells
internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("RetailCell", forIndexPath: indexPath) as! ResidentialTableViewCell
let entry = menuItems[indexPath.row]
let anotherEntry = menuItemsFiltered[indexPath.row]
if self.resultSearch.active
{ //Error in this block
cell.RetailLabel.text = menuItemsFiltered[indexPath.row]
//cell.RetailImage.image = anotherEntry
}
else
{ //All good here
cell.RetailImage.image = UIImage(named: entry["Image"]!)
cell.RetailLabel.text = entry["Name"]!
}
UPDATE: Changed from a dictionary to an array of Tuples:
var menuItems = [(name : "20/20 Cafe", image: "20_20Cafe.jpg"),
(name: "Au Bon Pain", image: "AuBonPain.jpg")]
var menuItemsFiltered: [(name: String, image: String)] = []
In my table view if / else statements
if self.resultSearch.active
{
cell.RetailLabel.text = menuItemsFiltered[indexPath.row].name
cell.RetailImage.image = UIImage(named: menuItemsFiltered[indexPath.row].image)
}
else
{
cell.RetailImage.image = UIImage(named: menuItems[indexPath.row].image)
cell.RetailLabel.text = menuItems[indexPath.row].name
}

Index of JSON Array Swift

I am using this library to parse an API endpoint that returns an array: https://github.com/SwiftyJSON/SwiftyJSON
I am grabbing an array fetched from a JSON response and I am trying to feed it into a table.
Right after my class in my view controller is declared, I have
var fetched_data:JSON = []
Inside of my viewDidLoad method:
let endpoint = NSURL(string: "http://example.com/api")
let data = NSData(contentsOfURL: endpoint!)
let json = JSON(data: data!)
fetched_data = json["posts"].arrayValue
To feed the table, I have:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell1")! as UITableViewCell
cell.textLabel?.text = self.fetched_data[indexPath.row]
return cell
}
I am getting this error, when trying to set the cell textLabel:
Cannot subscript a value of a type ‘JSON’ with an index type of ‘Int’
How do I do this properly and get this to work?
You are declaring fetched_data as JSON
var fetched_data:JSON = []
but you are assigning Array to it:
fetched_data = json["posts"].arrayValue
Lets change the type to array of AnyObject:
var fetched_data: Array<AnyObject> = []
and then assigning should be like this (we have [AnyObject] so we need to cast):
if let text = self.fetched_data[indexPath.row] as? String {
cell.textLabel?.text = text
}
Edit: You also need to remember to assign correct Array, by doing arrayObject instead of arrayValue:
fetched_data = json["posts"].arrayObject

Resources