How to load data in UITableView cell from structure - ios

I am trying to load data from a structure to table view cell, I created a custom cell with three label in it. I have three text field in the view controller and a add button I want that when I fill these three text field and press add it will store these three values in a structure and reload the data of table view. Structure is in other file.
Here is code for structure in DataMaster.swift
struct jobData
{
var CompanyName:Array<String> = ["ram"]
var job:Array<String> = ["shyam"]
var desc:Array<String> = ["dfdf"]
}
Code for addButton function
#IBAction func addButtonTapped(sender: AnyObject) {
var company = txtCompName.text
var job = txtJob.text
var description = txtDesc.text
data.CompanyName.append(company)
data.desc.append(description)
data.job.append(job)
self.jobTableView.reloadData()
print(data.CompanyName)
txtCompName.resignFirstResponder()
txtJob.resignFirstResponder()
txtDesc.resignFirstResponder()
}
The problem is in this code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as jobTableViewCell
cell.compLabel.text = data.CompanyName[indexPath.row]
cell.jobLabel.text = data.job[indexPath.row]
cell.descLabel.text = data.desc[indexPath.row]
return cell
}
when it reaches to this code to load data in table it crashes
Thread 1:EXC_BREAKPOINT(code=EXC_I386_BPT,subcode=0x0)

Here below is code.
struct jobData
{
var CompanyName:String!
var job:String!
var desc:String!
}
Take an array as var datas = [jobData]()
Now in Action method
#IBAction func addButtonTapped(sender: AnyObject) {
var company = txtCompName.text
var job = txtJob.text
var description = txtDesc.text
let dataObject = jobData(company: company, job: job, desc: description)
datas.append(dataObject)
self.jobTableView.reloadData()
txtCompName.resignFirstResponder()
txtJob.resignFirstResponder()
txtDesc.resignFirstResponder()
}
Now in cellForRowAtIndex method
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! jobTableViewCell
let data = datas[indexPath.row]
if let companyName = data.CompanyName {
cell.compLabel.text = companyName
}
if let job = data.job {
cell.jobLabel.text = job
}
if let descr = data.desc {
cell.descLabel.text = descr
}
return cell
}
in numberofRowsInSection method return datas.count
Check why data.CompanyName is empty and make sure all text field will have text.

Related

UISwitch in tableview row

In the code below I'm populating my table with some data. The switches are off which they don't have to be. In the storyboard I defined it as On.
Cell:
var switchHandler: ((Bool)->Void)?
#IBAction func switchChanged(_ sender: UISwitch) {
self.switchHandler?(sender.isOn)
}
View controller:
var selectedCells = Set<IndexPath>()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SmsCell") as? SmsTableViewCell
cell?.PhonNumberLbl.text = data![indexPath.section].contacts[indexPath.row]?.phoneNumber
cell?.NameLbl.text = data![indexPath.section].contacts[indexPath.row]?.name
cell?.selectedTF.isOn = (data![indexPath.section].contacts[indexPath.row]?.selected)!
cell?.selectedTF.isOn = self.selectedCells.contains(indexPath)
cell?.switchHandler = { (switchState) in
if switchState {
self.selectedCells.insert(indexPath)
} else {
self.selectedCells.remove(indexPath)
}
}
return cell!
}
Model:
typealias smsModelList = [SmsModel]
struct SmsModel:Codable {
var unitNo:Int?
var unitPlaque:String?
var billText:String?
var contacts:[ContactsModel?]
}
typealias contactlistmodel = [ContactsModel]
struct ContactsModel:Codable
{
var id :Int?
var selected :Bool?
var phoneNumber : String?
var name : String?
}
Does anybody see somthing wrong which turns off the switch?
First of all as you force unwrap the cell anyway do it in the dequeue line to avoid the unnecessary amount of question marks and use the API to return a non-optional cell
let cell = tableView.dequeueReusableCell(withIdentifier: "SmsCell", for: indexPath) as! SmsTableViewCell
To fix your issue update the selected property of the ContactsModel struct directly and forget the extra selectedCells array. Further declare – at least – selected as non-optional, practically there is no maybe state. And declare also all data source arrays (data / contacts) as non-optional, cellForRow is called only if there is an item at the particular indexPath by default.
struct ContactsModel : Codable {
...
var selected : Bool
...
}
...
let cell = tableView.dequeueReusableCell(withIdentifier: "SmsCell", for: IndexPath) as! SmsTableViewCell
let contact = data[indexPath.section].contacts[indexPath.row]
cell.PhonNumberLbl.text = contact.phoneNumber
cell.NameLbl.text = contact.name
cell.selectedTF.isOn = contact.selected
cell.switchHandler = { [unowned self] switchState in
// as the structs are value types you have to specify the full reference to the data source array
self.data[indexPath.section].contacts[indexPath.row].selected = switchState
}
Consider to use classes rather than structs in this case then you can shorten the closure
cell.switchHandler = { switchState in
contact.selected = switchState
}
You use both
cell?.selectedTF.isOn = (data![indexPath.section].contacts[indexPath.row]?.selected)!
cell?.selectedTF.isOn = self.selectedCells.contains(indexPath)
so isOn property of the switch is controlled from 2 sides , so you have to decide which line that should be commnented , plus don't depend on storyboard prototype cell setup as because of cell reusing it' ll be changed , if you want to make them all on by default then change the var selectedCells to contain all possible indexPaths and comment the other one

Passing XML Array Data to CollectionView via TableView

I'm attempting to pass an array of data from the view controller to the collection view cells. My collectionview is currently in a tableview. I have tried using delegation/protocols and creating arrays in the class and have not been able to successfully pass the data to my collectionview.
My code is a follows:
View Controller:
var ageUnder10: [MissingPerson] = []
var age10Plus: [MissingPerson] = []
var age15Plus: [MissingPerson] = []
if let ageRange = ageRange {
switch ageRange {
case .ageUnder10:
let ageUnder10Array = MissingPerson()
ageUnder10Array.title = self.missingPerson.title
ageUnder10Array.desc = self.missingPerson.desc
ageUnder10Array.url = self.missingPerson.url
self.ageUnder10.append(ageUnder10Array)
case .age10Plus:
let age10PlusArray = MissingPerson()
age10PlusArray.title = self.missingPerson.title
age10PlusArray.desc = self.missingPerson.desc
age10PlusArray.url = self.missingPerson.url
self.age10Plus.append(age10PlusArray)
case .age15Plus:
let age15PlusArray = MissingPerson()
age15PlusArray.title = self.missingPerson.title
age15PlusArray.desc = self.missingPerson.desc
age15PlusArray.url = self.missingPerson.url
self.age15Plus.append(age15PlusArray)
}
} else {
print("No valid age found")
}
Tableview Cell:
class TableViewCell: UITableViewCell {
var ageUnder10 = [MissingPerson]()
var age10Plus = [MissingPerson]()
var age15Plus = [MissingPerson]()
}
These values are being populated from an XML url
The categories are being created via scanner, scanning the values of a item in the xml (to create ageRange)
I have titleforheader and header names populated from a separate array in the view controller class
I figured it out, I needed to use a struct to pass the data. Also, create an instance of the array in the tableview class and write a function to fill the collectionView cell.
Example:
CustomTableViewCell:
customArray: [CustomArray]()
func configureCollectionCell(with array: [CustomArray]) {
self.customArray = customArray
}
ViewController Class:
var customArray = [CustomArray]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as? CustomTableViewCell {
cell.configureCollectionCell(with: customArray)
return cell
}

Best way of working with ListView

Hey guys I´m in the process of learning swift right now and I try to program a Game. I want to show a list with items and different attributes to these Items.
So first I have User choice of where they can select either Food or Toys or other stuff coming in the future. Here I tried to only do one ViewController and change the stuff inside depending on the choice. Right now I have these Items in an Array from a Class.
They look like this:
class FoodData {
var name: String
var description = "Basic Food"
var owned = 0
var taste = 0
var price = 0
var water = 0
var image = "default.png"
init(name: String){
self.name=name
}
}
class ToyData {
var name: String
var description = "Basic Item"
var owned = 0
var price = 0
var joy = 0
var image = "default.png"
init(name: String){
self.name=name
}
}
I initialise these with:
var foodLoad=[FoodData]()
func loadFoodData(){
foodLoad.append(FoodData(name: "IceCream"))
foodLoad[0].description="Very Cold"
foodLoad[0].owned=10
}
Same style for the Toys. Now I have these two Classes in two Arrays called foodLoad[i] and toyLoad[I]
For the Table View I fill it with the protocols
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let shopCell = tableView.dequeueReusableCell(withIdentifier: shopCellIdentifier, for: indexPath) as! ShopCellStyle
shopCell.shopNameLabel?.text = shopData[indexPath.row].name
shopCell.shopImageView?.image = UIImage(named: shopData[indexPath.row].image)
shopCell.shopPriceLabel?.text = String(shopData[indexPath.row].price) + currency
return shopCell
So my Idea was to assign shopData with the User choice.
But if I assign shopData = foodLoad, I can't change that to toyLoad anymore. So maybe you can give me a hint of how to solve this the best way.
for your cellForRowAt indexPath:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let shopCell = tableView.dequeueReusableCell(withIdentifier: "shopCellIdentifier", for: indexPath) as! ItemCell
if selection == "food" {
shopCell.shopNameLabel?.text = foodLoad[indexPath.row].name
shopCell.shopImageView?.image = UIImage(named:
foodLoad[indexPath.row].image)
shopCell.shopPriceLabel?.text = String(foodLoad[indexPath.row].price) + currency
}
else if selection == "toys" {
shopCell.shopNameLabel?.text = toyLoad[indexPath.row].name
shopCell.shopImageView?.image = UIImage(named:
toyLoad[indexPath.row].image)
shopCell.shopPriceLabel?.text = String(toyLoad[indexPath.row].price) + currency
}
return shopCell
}
You'd also want the numberOfRowsInSection UITableView function. Call tableview.reloadData() when the user changes the type selection.

How do I transfer multiple selected table view cells data to the next view controller in Swift?

So I have a lot of code already in place for this but I am getting some errors:
My Current code is :
func createGroupMessagesButton() {
dismissViewControllerAnimated(true) {
let user = self.tableView.indexPathsForSelectedRows
self.messagesController2?.showChatLogController(user)
}
}
The code above is meant to dismiss the current view controller, and pass all of the data into a function on the next view. That functions code is:
func showChatLogController(user: User) {
let chatLogController = ChatLogController(collectionViewLayout: UICollectionViewFlowLayout())
chatLogController.user = user
chatLogController.hidesBottomBarWhenPushed = true
navigationController?.pushViewController(chatLogController, animated: true)
}
The function above then pushes to another controller with that data that was passed down to the function above.
The only problem is that when I first try to pass the data I get an error that states:
Cannot convert value of type [NSIndexPath]? to expected type argument User
PS: User is an array that I have created.
This is my user array:
class User: NSObject {
var id: String!
var fullName: String!
var email: String!
var userPhoto: String!
var homeAddress: NSArray!
var schoolOrWorkAddress: String!
}
To sum up my issue I am having trouble passing the data of multiple selected table view cells.
If you would like to know how I pass one selected cells data this is how:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView.allowsMultipleSelectionDuringEditing != true {
dismissViewControllerAnimated(true) {
let user = self.users[indexPath.row]
self.messagesController?.showChatLogController(user)
}
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as! UserCell
let user = users[indexPath.row]
cell.textLabel?.text = user.fullName
cell.detailTextLabel?.text = user.email
if let userPhoto = user.userPhoto {
cell.profileImageView.loadImageUsingCacheWithUrlString(userPhoto)
}
return cell
}
An NSIndexPath is a construct to get a path to a specific row in a specific section.
The self.tableView.indexPathsForSelectedRows returns you a list of selected rows, so you'll then have to loop through them and use the row-attribute to find the corresponding user in your complete list of users. Also note that you most likely want to pass an Array of User instead of just one.
This is conceptional code of the top of my head, that should lead you in the correct direction.
func createGroupMessagesButton() {
dismissViewControllerAnimated(true) {
let selectedUserRows = self.tableView.indexPathsForSelectedRows
var selectedUsers = [User]
for let selectedUserRow in selectedUserRows {
selectedUsers.append(self.users[selectedUserRow.row]!)
}
self.messagesController2?.showChatLogController(selectedUsers)
}
}

Matching title with the Image name in UISearchController Swift

I have a tableviewController where I have a SearchBar. When I type in search box a cafeteria name then wrong image displays with the found name.
Here is my variables: Should I declare my dictionary array with title and image in another syntax format?
#IBOutlet weak var RetailTableView: UITableView! //our TableView
var resultSearch = UISearchController() //our UISearchbar
var menuItems = [["20/20 Cafe" : "20_20Cafe.jpg"],
["Au Bon Pain": "AuBonPain.jpg"]]
var menuItemsFiltered = [(String)]()
Here is my TableViewFunc:
internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("RetailCell", forIndexPath: indexPath) as! ResidentialTableViewCell
let entry = menuItems[indexPath.row]
let image = UIImage(named: RetailImagesArray[indexPath.row])
if self.resultSearch.active
{
cell.RetailLabel.text = menuItemsFiltered[indexPath.row]
}
else
{
cell.RetailImage.image = image
cell.RetailLabel.text = entry.keys //Not Working
}
My search function is not working either
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.FilteredArray.removeAll(keepCapacity: false)
let searchText = searchController.searchBar.text!.lowercaseString
FilteredArray = RetailPlacesArray.filter({$0.lowercaseString.rangeOfString(searchText) != nil})
RetailTableView.reloadData()
}
Please help, What I am doing wrong?
rangeOfString does not return nil if the string is not found, but an NSRange with the location NSNotFound.

Resources