I have Created two Dictionary of question and answer , and I have created two label in my table view for displaying question and their options serial wise , but after displaying the result into the table view it is shown as the given screenshot , help me to show these data in standard for of question and answer with options
*I have created Dictionary of two*
`[Int:String]`and [Int:Array<String>]
, *and now I want access it in my Table view serially with dictionary1 in question label and dictionary2 in answer label;*
Code --
var dictionary1:[Int:String] =
[0:"Whether you have experienced Pricking-pain, Desquamation,itching or dry skin sensation during seasonal alternate.",
1:"Whether your skin apt to flush( Redness) in hot humid environment ",
2:"Whether your skin has multiple disernible dilated capillaries.",
3:"whether you have once been diagnosed atopic dermatitis or seborrheic dermatitis."]
Dictionary2 for creating options to the questions
var dictionary2 : [Int:Array<String>] =
[0:["Never","Seldom","Usually","Always"],
1:["Never","Seldom","Usually","Always"],
2:["Never","Seldom","Usually","Always"],
3:["Yes", "No"]]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dictionary1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.questionLabel.text = dictionary1[indexPath.row]
cell.questionLabel.textColor = UIColor.black
let arr = dictionary2[indexPath.row]
var strr = String()
for str in arr! {
strr = strr + str
}
cell.optionsLabel.text = strr
cell.optionsLabel.textColor = UIColor.black
return cell
}
}
// HERE IS THE SCREENSHOT OF MY TABLE VIEW , IT IS NOT SHOWING THE DATA IN MULTILINE AND THE OPTIONS AND THE QUESTION ARE OVERLAPPING
[![enter image description here][1]][1]
List item
[1]: https://i.stack.imgur.com/Erpvq.png
Replace below delegate with yours:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
// TO Display Single Dictionary Data
cell.textLabel?.text = dictionary1[indexPath.row]
// To display Array of string stored in dictionary
cell.textLabel?.text = dictionary2[indexPath.row]?.joined(separator: "\n")
return cell
}
For 2nd Requirement
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dictionary1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
// FOR FIRST DICTIONARY
cell.lblFirst?.text = dictionary1[indexPath.row]
// FOR SECOND DICTIONARY
cell.lblSecond?.text = dictionary2[indexPath.row]?.joined(separator: "\n")
return cell
}
Note: I wanted to make it a comment, but I also wanted to share this image so I answered, but it's a hint, not the complete answer.
The function you are using takes an array of String as input. you can see the below screen for any function by pressing the option key and clicking the function body.
You need to pass the key as a string. then your dictionary must have a key type as String. Once you make the key a string.
Possible solutions are:
if you are keeping key as Int, then use: dictionary1[indexPath.row]
if you make your key as a string then use: dictionary1["\(indexPath.row)"]
(Just for this case) If you want to show them in a sequence only like 0th element 1st element.. then why not use an Array instead of Dictionary.
arry = ["1st description","2nd description"]
and then use
cell.label.text = arry[indexPath.row]
Related
I am new to Swift and I'm making my first application, so the question will be asked will be in a simpler way, not exactly with programming terms.
I have a table with names, which are also written in the Firebase. I need the ones I will select, and I press the save button, to write them (selected rows with names) in the database as a new child.
And my code is:
let uid = Auth.auth().currentUser?.uid
var ref: DatabaseReference!
var guestList = [GuestModel]()
var indexArray: [Int] = []
func addTable(){
ref = Database.database().reference().child("userInfo").child(uid!).child("tables")
let key = ref.childByAutoId().key
let table = ["id": key, "tableName": entertableNameTextField.text! as String, "tableCapacity": tableCapacityTextField.text! as String, "tableNo": enterTableNumber.text! as String, "guestsOnTable" : "\(indexArray)" as String]
ref.child(key!).setValue(table)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return guestList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "guestListCell", for: indexPath) as! GuestListToTableTableViewCell
let guest: GuestModel
guest = guestList[indexPath.row]
cell.fullNameLabel.text = guest.guestName! + " " + guest.guestFamilyName!
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
indexArray.append(indexPath.row)
}
you can take a key(in Firbase) and set is default false while click on it set it true.
and your logic will be.
in didselect method
you need to update that key to true.
tblView.reloadData()
in cellforRow method
check selected true change your cell design as well you want.
I have a data source in this form:
struct Country {
let name: String
}
The other properties won't come into play in this stage so let's keep it simple.
I have separated ViewController and TableViewDataSource in two separate files. Here is the Data source code:
class CountryDataSource: NSObject, UITableViewDataSource {
var countries = [Country]()
var filteredCountries = [Country]()
var dataChanged: (() -> Void)?
var tableView: UITableView!
let searchController = UISearchController(searchResultsController: nil)
var filterText: String? {
didSet {
filteredCountries = countries.matching(filterText)
self.dataChanged?()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredCountries.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let country: Country
country = filteredCountries[indexPath.row]
cell.textLabel?.text = country.name
return cell
}
}
As you can see there is already a filtering mechanism in place.
Here is the most relevant part of the view controller:
class ViewController: UITableViewController, URLSessionDataDelegate {
let dataSource = CountryDataSource()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.tableView = self.tableView
dataSource.dataChanged = { [weak self] in
self?.tableView.reloadData()
}
tableView.dataSource = dataSource
// Setup the Search Controller
dataSource.searchController.searchResultsUpdater = self
dataSource.searchController.obscuresBackgroundDuringPresentation = false
dataSource.searchController.searchBar.placeholder = "Search countries..."
navigationItem.searchController = dataSource.searchController
definesPresentationContext = true
performSelector(inBackground: #selector(loadCountries), with: nil)
}
The loadCountries is what fetches the JSON and load the table view inside the dataSource.countries and dataSource.filteredCountries array.
Now, how can I get the indexed collation like the Contacts app has without breaking all this?
I tried several tutorials, no one worked because they were needing a class data model or everything inside the view controller.
All solutions tried either crash (worst case) or don't load the correct data or don't recognise it...
Please I need some help here.
Thank you
I recommend you to work with CellViewModels instead of model data.
Steps:
1) Create an array per word with your cell view models sorted alphabetically. If you have data for A, C, F, L, Y and Z you are going to have 6 arrays with cell view models. I'm going to call them as "sectionArray".
2) Create another array and add the sectionArrays sorted alphabetically, the "cellModelsData". So, The cellModelsData is an array of sectionArrays.
3) On numberOfSections return the count of cellModelsData.
4) On numberOfRowsInSection get the sectionArray inside the cellModelsData according to the section number (cellModelsData[section]) and return the count of that sectionArray.
5) On cellForRowAtindexPath get the sectionArray (cellModelsData[indexPath.section]) and then get the "cellModel" (sectionArray[indexPath.row]). Dequeue the cell and set the cell model to the cell.
I think that this approach should resolve your problem.
I made a sample project in BitBucket that could help you: https://bitbucket.org/gastonmontes/reutilizablecellssampleproject
Example:
You have the following words:
Does.
Any.
Visa.
Count.
Refused.
Add.
Country.
1)
SectionArrayA: [Add, Any]
SectionArrayC: [Count, Country]
SectionArrayR: [Refused]
SectionArrayV: [Visa]
2)
cellModelsData = [ [SectionArrayA], [SectionArrayC], [SectionArrayR], [SectionArrayV] ]
3)
func numberOfSections(in tableView: UITableView) -> Int {
return self.cellModelsData.count
}
4)
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionModels = self.cellModelsData[section]
return sectionModels.count
}
5)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sectionModels = self.cellModelsData[indexPath.section]
let cellModel = sectionModels[indexPath.row]
let cell = self.sampleCellsTableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier",
for: indexPath) as! YourCell
cell.cellSetModel(cellModel)
return cell
}
I am fetching previously selected categorylist from the server. say for an example.cateogrylist i fetched from the server was in following formate
categoryid : 2,6,12,17
now what i need to do is want to enable checkmark in my tableview based on this categorylist,for that purpose i converted this list into an [Int] array like this :
func get_numbers(stringtext:String) -> [Int] {
let StringRecordedArr = stringtext.components(separatedBy: ",")
return StringRecordedArr.map { Int($0)!}
}
in viewDidLoad() :
selectedCells = self.get_numbers(stringtext: UpdateMedicalReportDetailsViewController.catId)
print(myselection)
while printing it's giving me results like this : [12,17,6,8,10]
i want to enable checkimage based on this array.I tried some code while printing its giving me the right result like whatever the categories i selected at the time of posting ,i am able to fetch it but failed to place back this selection in tableview.Requirement : while i open this page it should show me the selection based on the categorylist i fetched from the server.
var selectedCells : [Int] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell1 = table.dequeueReusableCell(withIdentifier: "mycell") as! catcell
cell1.mytext.text = categoriesName[indexPath.row]
if UpdateMedicalReportDetailsViewController.flag == 1
{
selectedCells = self.get_numbers(stringtext: UpdateMedicalReportDetailsViewController.catId)
cell1.checkimage.image = another
print(selectedCells)
}
else
{
selectedCells = []
cell1.checkimage.image = myimage
}
return cell1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = table.cellForRow(at: indexPath) as! catcell
cell.checkimage.image = myimage
if cell.isSelected == true
{
self.selectedCells.append(indexPath.row)
cell.checkimage.image = another
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = table.cellForRow(at: indexPath) as! catcell
if cell.isSelected == false
{
self.selectedCells.remove(at: self.selectedCells.index(of: indexPath.row)!)
cell.checkimage.image = myimage
}
}
output :
This is a very common use case in most apps. I'm assuming you have an array of all categories, and then an array of selected categories. What you need to do is in cellForRowAtIndexPath, check to see if the current index path row's corresponding category in the "all categories" array is also present in the "selected categories" array. You can do this by comparing id's etc.
If you have a match, then you know that the cell needs to be selected/checked. A clean way to do this is give your cell subclass a custom load method and you can pass a flag for selected/checked.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "mycell") as! catcell
let category = self.categories[indexPath.row] // Let's say category is a string "hello"
Bool selected = self.selectedCategories.contains(category)
cell.load(category, selected)
return cell
}
So with the code above, let's say that categories is just an array of category strings like hello, world, and stackoverflow. We check to see if the selectedCategories array contains the current cell/row's category word.
Let's say that the cell we're setting up has a category of hello, and selectedCategories does contain it. That means the selected bool gets set to true.
We then pass the category and selected values into the cell subclass' load method, and inside that load method you can set the cell's title text to the category and you can check if selected is true or false and if it's true you can display the checked box UI.
This has been killing me for a few hours now. I have a UITableViewController that has multiple data sections. My data source is simply an Array.
The problem I'm running into is that each section is repeating data from the array starting from the first index instead of "slicing" it as I expect it should.
Simplified example:
let sections = ["Section A", "Section B"]
let counts = [3, 5]
let source = ["a","b",c","d","e","f","g","h"]
// Output in simulator:
# Section A
- a
- b
- c
# Section B
- a
- b
- c
- d
- e
- and so on...
I would expect that "Section B" would be the next 5 results starting at "d" and not restart from the first index.
The relevant code is pretty standard stuff:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count // returns 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return counts[section] // returns correct data
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let data = source[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MyTableViewCell
// some cell formatting, populate UILabels, etc
cell.testLabel.text = data["test"].string
return cell
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("Header") as! MyTableViewHeaderCell
headerCell.backgroundColor = UIColor.grayColor()
headerCell.testHeaderLabel.text = sections[section]
return headerCell
}
Initial searching of SO led me to believe it's a cell reuse issue but after overriding prepareForReuse in my cell class, I don't think thats it.
Expected Results
# Section A
- a
- b
- c
# Section B
- d
- e
- f
- g
- h
Like I said, I'm expecting that dividing the TableView data in to sections would keep a reference to the array pointer and continue where it left off instead of starting back at 0 for each section.
Any thoughts or suggestions?
indexPath.row always returns the row-number inside a section.
In your second section, you need to add the number of rows displayed in all sections before.
Change let data = source[indexPath.row] to something like this:
let data = source[indexPath.row+counts[0]]
If you add more sections, this will be a bit more complicated to calculate.
Other idea:
If it is possible, you could rearrange your array. You could make a two-dimensional array. The main array would include arrays with the data for each section.
To display it, you' need to use indexPath.section, too.
dataArray[indexPath.section][indexPath.row]
Using the idea of FelixSFD, but with a little logical modification, so you can work dynamically:
Change this:
let data = source[indexPath.row]
for this:
var countIndex = indexPath.row
for section in 0...indexPath.section {
countIndex += counts[section]
}
let data = source[countIndex]
Be careful with this approach because you may have some performance issues on large tableViews.
If you can rearrange your array:
change
let source = ["a","b",c","d","e","f","g","h"]
into
let source = [["a","b","c"],["d","e","f","g","h"]]
and change
let data = source[indexPath.row]
into
let data = source[indexPath.section][indexPath.row]
I had the same problem, but with more complex situation, and i needed more dynamically way of doing it. Sure i could rearrange my data, to use two-dimensional array, but i don't want to handle it later. So i did it like this.
I am pulling my data from firebase, so i never know, how many sections/arrays i will have.
Creating an array, to insert amount of items in array.
var counterTableView = [Int]()
Filling array with 0, without doing it, i was getting errors later. (Index out of range)
override func numberOfSections(in tableView: UITableView) -> Int {
for i in 0...Array(Set(self.sections)).count {
counterTableView.insert(0, at: i)
}
counterTableView.removeLast(counterTableView.count-Array(Set(self.sections)).count-1)
return Array(Set(self.sections)).count
}
Next step, is to fill the amount of items in one section in array
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
counterTableView[section+1] = counts[section] + counterTableView[section]}
Last step, showing the data in cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.textLabel.text = source[indexPath.row+counterTableView[indexPath.section]]}
I have a API that hands back a string of numbers based on a User.
Once the API Request is made the function places the numbers into an Array.
var usernumbers = userResponse["Numbers"] as NSArray
The debugger PrintLn shows:
( 16467621007,
14152555613,
14046206007
)
When I hand this to UITableView, how do I split up the array so that each number goes into a separate cell?
Ive tried:
let rowData: NSArray = tableData (usernumbers has been handed to table data)
I've tried:
cell.textLabel?.text = rowData.row (and all varieties of)
Where am I going wrong?
If i understood your problem correctly, this is what you are looking for,
cell.textLabel?.text = rowData[indexPath.row] as String
Edit:
let numberValue : NSNumber = rowData[indexPath.row] as NSNumber
let text : String = numberValue.stringValue // add nil check
cell.textLabel?.text = text
You can directly assign like
cell.textLabel?.text = numberValue.stringValue - if you are sure there won't be a nil value
Use rowData[indexPath.row] where indexPath.row is the current cell starting from 0
private let data = Array(1...9)
then...
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
and in your :
func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {...
all the usual stuff.
cell.textLabel?.text = String(format: "the magic number is : %.f", data[indexPath.row])
}