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.
Related
What happens right now:
numberOfRowsInSection correctly gets the number of rows in each section by using a dictionary of words with same starting letter as section heading. So Australia and Argentina go in section A.
Problem is that didSelectRowAt can't use that same dictionary to set the cell because well it needs to select a different part of the struct (so didSelect and the precursors of the dictionary are in the same struct)
So in cellForRowAt, I match it to didSelectRowAt, so that the didSelectRowAt works perfectly. Problem then is for each section, all alphabet elements are included, not only the ones with the same 1st letter as the section title.
So for A, it would include something like Australia, Argentina. For B it would include Australia, Argentina, Brazil. For C Australia, Argentina, Brazil, Canada. Instead it should only include Canada at C etc
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
let aveKey = sectionTitle[indexPath.section]
if let aveValue = aveDict[aveKey] {
cell.textLabel?.text = dropDownOptions[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.delegate.dropDownPressed(string: dropDownOptions1[indexPath.row])
print(dropDownOptions[indexPath.row])
self.tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return aveDict[sectionTitle[section]]?.count ?? 0
}
Part B: The structure
struct CountryCodeItem {
let prefix: String
let country: String
let dashy: String
var displayText: String {
"\(prefix) \(country)"
}
}
//in viewDidLoad
button.dropView.dropDownOptions = countryCodes.map { $0.displayText }
button.dropView.dropDownOptions1 = countryCodes.map { $0.prefix }
button.dropView.dropDownOptions2 = countryCodes.map { $0.country}
Part C: The dictionary
func createAvengersDict() {
for avenger in dropDownOptions2 {
let firstLetterIndex = avenger.index(avenger.startIndex, offsetBy: 1)
let avengerKey = String(avenger[..<firstLetterIndex])
if var avengerValues = avengersDict[avengerKey] {
avengerValues.append(avenger)
avengersDict[avengerKey] = avengerValues
} else {
avengersDict[avengerKey] = [avenger]
}
}
avengerSectionTitles = [String](avengersDict.keys)
avengerSectionTitles = avengerSectionTitles.sorted(by: { $0 < $1
})
}
I am working on an small project where I have an app that takes in tvshow information entered by the user and displays it in a custom tableview cell. I would like to sort the shows as they are entered based on which current episode the user is on. I know this code works because I tested it with print statements and it sorts the array but it does not sort on the simulator. So I just was curious where I should place this so that it sorts on the app side.
func sortShows() {
let sortedShows = tvShows.sorted { $0.currentEpisode > $1.currentEpisode}
TVShowTableView.reloadData()
print(sortedShows)
}
Here is where I am currently placing it inside my view controller
extension TVShowListViewController: AddTVShowDelegate {
func tvShowWasCreated(tvShow: TVShow) {
tvShows.append(tvShow)
dismiss(animated: true, completion: nil)
TVShowTableView.reloadData()
sortShows()
}
}
In this part of your code:
func sortShows() {
// here you are creating a NEW array
let sortedShows = tvShows.sorted { $0.currentEpisode > $1.currentEpisode}
// here you tell the table view to reload with the OLD array
TVShowTableView.reloadData()
print(sortedShows)
}
In your controller class, you probably have something like:
var tvShows: [TVShow] = [TVShow]()
and then you populate it with shows, like you do with a new show:
tvShows.append(tvShow)
Then your controller is doing something like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tvShowCell", for: indexPath) as! TVShowCell
cell.tvShow = tvShows[indexPath.row]
return cell
}
What you want to do is add another var to your class:
var sortedShows: [TVShow] = [TVShow]()
then change your sort func to use that array:
func sortShows() {
// use the existing class-level array
sortedShows = tvShows.sorted { $0.currentEpisode > $1.currentEpisode}
// here you tell the table view to reload
TVShowTableView.reloadData()
print(sortedShows)
}
and change your other funcs to use the sortedShows array:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// use sortedShows array
return sortedShows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tvShowCell", for: indexPath) as! TVShowCell
// use sortedShows array
cell.tvShow = sortedShows[indexPath.row]
return cell
}
and you'll want to call sortShows() at the end of viewDidLoad() (or wherever you are getting your initial list of shows).
Edit
Another way you might use cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tvShowCell", for: indexPath) as! TVShowCell
// use sortedShows array
let tvShow = sortedShows[indexPath.row]
cell.showTitleLable.text = tvShow.title
cell.showDecriptionLable.text = tvShow.description
return cell
}
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 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]
I'm just in the process of putting a prototype app together in Swift 3.0.
At the minute, all API information is Parsed in to table cells. What I was hoping to do was introduce the facility where if I set an "Active" column in my database to "no" then how could I prevent that cell from showing in the table view?
Currently the code is this:
func configure(offence: Offence) {
if let name = offence.name, let act = offence.act {
self.textLabel?.text = name
self.detailTextLabel?.text = act
}
I've tried playing around with if/else statements but I'm not having much luck.
if your Offences have an active property you can use it to filter your server response and only show those with the active property set to true. something like this:
struct Offence {
var name: String
var active: Bool
}
class YourViewController: UITableViewController {
// all the offences you get from the server
let offences: [Offence] = []
// only the active offences - use those as your datasource!
var visibleOffences: [Offence] {
return offences.filter { $0.active }
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return visibleOffences.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCell", for: indexPath)
cell.textLabel?.text = visibleOffences[indexPath.row].name
return cell
}
}