i have a textfield, when the user tap on it, a table1 appear with a list of countries currency, then the user choose a currency and add it to table2, i can add one currency , when i add another one to table2 the app crash with the following error: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path ( {length = 2, path = 0 - 1})'
class CurrencySecondStep: UIViewController ,UITableViewDataSource, UITableViewDelegate,UITextFieldDelegate {
#IBOutlet weak var tableViewAddedByUser: UITableView!
#IBOutlet weak var amountToBeExchanged: UILabel!
#IBOutlet weak var tableViewFor: UITableView!
#IBOutlet weak var textFieldFor: UITextField!
//cell identifier
let cellReuseIdentifier = "cell"
//struct
struct Currency {
var country = String()
var currencyCode = String()
var currencyFlag = UIImage()
}
var addedCurrencyByUserArray = [Currency]()
var currencyArr = [
Currency(country: "United Arab Emirates Dirham", currencyCode: "AED",currencyFlag: UIImage(named:"United-Arab-Emirates")!),
Currency(country: "US Dollar", currencyCode: "USD",currencyFlag: UIImage(named:"United-States")!),
Currency(country: "Afghan Afghani (1927–2002)", currencyCode: "AFA",currencyFlag: UIImage(named:"Afghanistan")!),
Currency(country: "Albania Lek", currencyCode: "ALL",currencyFlag: UIImage(named:"Albania")!),
Currency(country: "Algerian Dinar", currencyCode: "DZD",currencyFlag: UIImage(named:"Algeria")!),
Currency(country: "Angolan Kwanza", currencyCode: "AOA",currencyFlag: UIImage(named:"Angola")!),
Currency(country: "Argentine Peso", currencyCode: "ARS",currencyFlag: UIImage(named:"Argentina")!),
Currency(country: "Armenian Dram", currencyCode: "AMD",currencyFlag: UIImage(named:"Armenia")!)
]
//searched results
var filteredCurrenciesOffer = [Currency]()
//currency code to be sent to google finance
var currencyCodeOffer = ""
var currencyPassed = ""
var countryChoice = ""
var countryCodeChoice = ""
var countryflagChoice = UIImage()
#IBAction func textFieldChanged(_ sender: AnyObject) {
tableViewFor.isHidden = true
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableViewFor.delegate = self
tableViewFor.dataSource = self
tableViewFor.isHidden = true
textFieldFor.delegate = self
textFieldFor.addTarget(self, action: #selector(textFieldActive), for: UIControlEvents.touchDown)
textFieldFor.addTarget(self, action:#selector(textFieldDidChange) , for: UIControlEvents.editingChanged)
//hide or show keyboard
textFieldFor.addTarget(self, action: #selector(textFieldShouldReturn), for: UIControlEvents.touchDown)
amountToBeExchanged.text = currencyPassed
//table added By User
tableViewAddedByUser.delegate = self
tableViewAddedByUser.dataSource = self
tableViewAddedByUser.isHidden = true
}
when the user press add Button to insert the second element the app crash
#IBAction func addPressed(_ sender: Any) {
if(textFieldFor.text == ""){
displayError(title: "Currency Type",message:"Please Pick Your Currency")
}else{
tableViewAddedByUser.isHidden = false
addedCurrencyByUserArray.append(Currency(country: countryChoice, currencyCode: countryCodeChoice,currencyFlag: countryflagChoice))
tableViewAddedByUser.beginUpdates()
let insert = IndexPath(row: addedCurrencyByUserArray.count - 1, section: 0)
tableViewAddedByUser.insertRows(at: [insert], with: .automatic)
tableViewAddedByUser.endUpdates()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: TextField Functions
func textFieldDidEndEditing(_ textField: UITextField) {
filteredCurrenciesOffer = currencyArr.filter { currencyGiven in
return currencyGiven.country.lowercased().contains(textFieldFor.text!.lowercased())
}
//reload table based on the user pick
tableViewFor.reloadData()
}
func textFieldDidChange(textField: UITextField) {
//update search based on user search
filteredCurrenciesOffer = currencyArr.filter { currencyGiven in
return currencyGiven.country.lowercased().contains(textFieldFor.text!.lowercased())
}
tableViewFor.reloadData()
}
// Toggle the tableView visibility when click on textField
func textFieldActive(textField: UITextField) {
tableViewFor.isHidden = !tableViewFor.isHidden
}
//hide keyboard
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// MARK: TableView Functions
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count:Int?
if (tableView == self.tableViewFor && textFieldFor.text != ""){
count = filteredCurrenciesOffer.count
}else if(tableView == self.tableViewFor && textFieldFor.text == ""){
count = currencyArr.count
}
if(tableView == self.tableViewAddedByUser){
count = addedCurrencyByUserArray.count
print("number of rows")
print(count!)
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableViewFor.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
var currency: Currency
if (tableView == self.tableViewFor){
if ( textFieldFor.text != "") {
currency = filteredCurrenciesOffer[indexPath.row]
} else {
currency = currencyArr[indexPath.row]
}
cell.flag.image = currency.currencyFlag
cell.country.text = currency.country
cell.currencyCode.text = currency.currencyCode
}
if (tableView == self.tableViewAddedByUser){
currency = addedCurrencyByUserArray[indexPath.row]
cell.flag.image = currency.currencyFlag
cell.country.text = currency.country
cell.currencyCode.text = currency.currencyCode
}
return cell
}
// MARK: UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var currency: Currency
if(tableView == tableViewFor){
if textFieldFor.text != "" {
currency = filteredCurrenciesOffer[indexPath.row]
} else {
currency = currencyArr[indexPath.row]
}
//add image to currency text field
let leftImageView = UIImageView()
leftImageView.image = currency.currencyFlag
let leftView = UIView()
leftView.addSubview(leftImageView)
leftView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
leftImageView.frame = CGRect(x: 10, y: 10, width: 20, height: 20)
textFieldFor.leftViewMode = .always
textFieldFor.leftView = leftView
//add country to currency text field
textFieldFor.text = currency.country
countryChoice = currency.country
countryCodeChoice = currency.currencyCode
countryflagChoice = currency.currencyFlag
currencyCodeOffer = currency.currencyCode
tableViewFor.isHidden = true
textFieldFor.endEditing(true)
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.0
}
//hide the table and keyboard
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch:UITouch = touches.first else
{
return;
}
if touch.view != tableViewFor
{
textFieldFor.endEditing(true)
tableViewFor.isHidden = true
}
}
func displayError(title:String,message:String){
// Create the alert controller
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
// Create the actions
let retryButton = UIAlertAction(title: "Ok", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alertController.addAction(retryButton)
}
}
I think the problem happens in your
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
On the first line you always dequeue a cell from the tableViewFor even when you need a cell for tableViewAddedByUser.
Try replacing the first line with this which will dequeue a cell from the tableView sent in the parameters instead:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
If that doesn't work then try without specifying the indexPath like so:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
Related
I have 2 ViewControllers and each ViewController have a UITableView.
In the MainViewController I have few rows and I want to add for each row different Tags from the second ViewController.
My tags are saved in a Dictionary (I don't know if is the best way but I was thinking that maybe I will avoid to append a tag twice using a Dict instead of Array).
The problem is that I don't append correctly the selected tags and I don't know how I should do it.
Here I've created a small project which reflect my issue: https://github.com/tygruletz/AppendTagsToCells
Here is the code for Main VC:
class ChecklistVC: UIViewController {
#IBOutlet weak var questionsTableView: UITableView!
//Properties
lazy var itemSections: [ChecklistItemSection] = {
return ChecklistItemSection.checklistItemSections()
}()
var lastIndexPath: IndexPath!
var selectedIndexPath: IndexPath!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
questionsTableView.reloadData()
}
}
extension ChecklistVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let itemCategory = itemSections[section]
return itemCategory.checklistItems.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return itemSections.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "checklistCell", for: indexPath) as! ChecklistCell
let itemCategory = itemSections[indexPath.section]
let item = itemCategory.checklistItems[indexPath.row]
cell.delegate = self
cell.configCell(item)
cell.vehicleCommentLabel.text = item.vehicleComment
cell.trailerCommentLabel.text = item.trailerComment
cell.tagNameLabel.text = item.vehicleTags[indexPath.row]?.name
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goChecklistAddComment" {
let addCommentVC = segue.destination as! ChecklistAddCommentVC
addCommentVC.delegate = self
}
if segue.identifier == "goChecklistAddTag" {
let checklistAddTag = segue.destination as! ChecklistAddTagVC
checklistAddTag.indexForSelectedRow = self.selectedIndexPath
checklistAddTag.tagsCallback = { result in
print("result: \(result)")
let item = self.itemSections[self.lastIndexPath.section].checklistItems[self.lastIndexPath.row]
item.vehicleTags = result
}
}
}
}
Here is the code for Tags ViewController:
class ChecklistAddTagVC: UIViewController {
// Interface Links
#IBOutlet weak var tagsTitleLabel: UILabel!
#IBOutlet weak var tagsTableView: UITableView!
// Properties
var tagsDictionary: [Int: Tag] = [:]
var tagsAdded: [Int:Tag] = [:]
var tagsCallback: (([Int:Tag]) -> ())?
var indexForSelectedRow: IndexPath!
override func viewDidLoad() {
super.viewDidLoad()
tagsTableView.tableFooterView = UIView()
tagsDictionary = [
1: Tag(remoteID: 1, categoryID: 1, name: "Tag1", colour: "red"),
2: Tag(remoteID: 2, categoryID: 1, name: "Tag2", colour: "blue"),
3: Tag(remoteID: 3, categoryID: 1, name: "Tag3", colour: "orange"),
4: Tag(remoteID: 4, categoryID: 1, name: "Tag4", colour: "black")
]
print("Received index for SelectedRow: \(indexForSelectedRow ?? IndexPath())")
}
}
extension ChecklistAddTagVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tagsDictionary.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "defectAndDamageTagCell", for: indexPath) as! ChecklistAddTagCell
cell.configCell()
cell.delegate = self
cell.tagNameLabel.text = tagsDictionary[indexPath.row + 1]?.name.capitalized
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
extension ChecklistAddTagVC: ChecklistAddTagCellDelegate{
// When the user press Add Tag then will be added in a dictionary and sent to ChecklistVC using a callback closure.
func addTagBtnPressed(button: UIButton, tagLabel: UILabel) {
if button.currentTitle == "+"{
button.setTitle("-", for: UIControl.State.normal)
tagLabel.textColor = UIColor.orange
tagsAdded = [0: Tag(remoteID: 1, categoryID: 1, name: tagLabel.text ?? String(), colour: "red")]
print(tagsAdded[0]?.name ?? String())
tagsCallback?(tagsAdded)
}
else{
button.setTitle("+", for: UIControl.State.normal)
tagLabel.textColor = UIColor.black
tagsAdded.removeValue(forKey: 0)
print(tagsAdded)
tagsCallback?(tagsAdded)
}
}
}
Here is a capture with my issue:
Thank you for reading this !
I fix it !
The solution is below. Also you can find the completed project at this link:
https://github.com/tygruletz/AppendCommentsToCells
MainVC:
class ChecklistVC: UIViewController {
#IBOutlet weak var questionsTableView: UITableView!
//Properties
lazy var itemSections: [ChecklistItemSection] = {
return ChecklistItemSection.checklistItemSections()
}()
var lastIndexPath: IndexPath!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
questionsTableView.reloadData()
}
}
extension ChecklistVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let itemCategory = itemSections[section]
return itemCategory.checklistItems.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return itemSections.count
}
// Set the header of each section
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let checklistItemCategory = itemSections[section]
return checklistItemCategory.name.uppercased()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "checklistCell", for: indexPath) as! ChecklistCell
let itemCategory = itemSections[indexPath.section]
let item = itemCategory.checklistItems[indexPath.row]
cell.delegate = self
cell.configCell(item)
cell.vehicleCommentLabel.text = item.vehicleComment
cell.trailerCommentLabel.text = item.trailerComment
let sortedTagNames = item.vehicleTags.keys.sorted(by: {$0 < $1}).compactMap({ item.vehicleTags[$0]})
print("Sorted tag names: \(sortedTagNames.map {$0.name})")
let joinedTagNames = sortedTagNames.map { $0.name}.joined(separator: ", ")
cell.tagNameLabel.text = joinedTagNames
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goChecklistAddComment" {
let addCommentVC = segue.destination as! ChecklistAddCommentVC
addCommentVC.delegate = self
}
if segue.identifier == "goChecklistAddTag" {
let addTagVC = segue.destination as! ChecklistAddTagVC
addTagVC.delegate = self
addTagVC.addedTags = itemSections[lastIndexPath.section].checklistItems[lastIndexPath.row].vehicleTags
}
}
}
extension ChecklistVC: ChecklistCellDelegate {
func tapGestureOnCell(_ cell: ChecklistCell) {
showOptionsOnCellTapped(questionsTableView.indexPath(for: cell)!)
}
func showOptionsOnCellTapped(_ indexPath: IndexPath){
let addComment = UIAlertAction(title: "📝 Add Comment", style: .default) { action in
self.lastIndexPath = indexPath
self.performSegue(withIdentifier: "goChecklistAddComment", sender: nil)
}
let addTag = UIAlertAction(title: "🏷 Add Tag ⤵", style: .default) { action in
self.showOptionsForAddTag(indexPath)
}
let actionSheet = configureActionSheet()
actionSheet.addAction(addComment)
actionSheet.addAction(addTag)
self.present(actionSheet, animated: true, completion: nil)
}
// A menu from where the user can choose to add tags for Vehicle or Trailer
func showOptionsForAddTag(_ indexPath: IndexPath){
self.lastIndexPath = indexPath
let addVehicleTag = UIAlertAction(title: "Add Vehicle tag", style: .default) { action in
self.performSegue(withIdentifier: "goChecklistAddTag", sender: nil)
}
let addTrailerTag = UIAlertAction(title: "Add Trailer tag", style: .default) { action in
self.performSegue(withIdentifier: "goChecklistAddTag", sender: nil)
}
let actionSheet = configureActionSheet()
actionSheet.addAction(addVehicleTag)
actionSheet.addAction(addTrailerTag)
self.present(actionSheet, animated: true, completion: nil)
}
func configureActionSheet() -> UIAlertController {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
actionSheet.addAction(cancel)
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){
actionSheet.popoverPresentationController?.sourceView = self.view
actionSheet.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
actionSheet.popoverPresentationController?.permittedArrowDirections = []
}
return actionSheet
}
}
// Receive Comments from ChecklistAddCommentVC using the Delegate Pattern
extension ChecklistVC: ChecklistAddCommentDelegate {
func receiveVehicleComment(vehicleComment: String?, trailerComment: String?) {
let item = itemSections[lastIndexPath.section].checklistItems[lastIndexPath.row]
item.vehicleComment = vehicleComment ?? String()
item.trailerComment = trailerComment ?? String()
questionsTableView.reloadData()
}
}
// Receive Tags from ChecklistAddTagVC using the Delegate Pattern
extension ChecklistVC: ChecklistAddTagVCDelegate{
func receiveAddedTags(tags: [Int : Tag]) {
let item = self.itemSections[self.lastIndexPath.section].checklistItems[self.lastIndexPath.row]
item.vehicleTags = tags
}
}
AddTagsVC:
protocol ChecklistAddTagVCDelegate {
func receiveAddedTags(tags: [Int: Tag])
}
class ChecklistAddTagVC: UIViewController {
// Interface Links
#IBOutlet weak var tagsTableView: UITableView!
// Properties
var tagsDictionary: [Int: Tag] = [:]
var addedTags: [Int: Tag] = [:]
var delegate: ChecklistAddTagVCDelegate?
var indexPathForBtn: IndexPath!
override func viewDidLoad() {
super.viewDidLoad()
tagsTableView.tableFooterView = UIView()
tagsDictionary = [
1: Tag(remoteID: 1, categoryID: 1, name: "Tag1", color: "red"),
2: Tag(remoteID: 2, categoryID: 1, name: "Tag2", color: "blue"),
3: Tag(remoteID: 3, categoryID: 1, name: "Tag3", color: "orange"),
4: Tag(remoteID: 4, categoryID: 1, name: "Tag4", color: "black")
]
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Added tags: \(addedTags.map {$1.name})")
setupButtons()
tagsTableView.reloadData()
}
}
extension ChecklistAddTagVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tagsDictionary.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "defectAndDamageTagCell", for: indexPath) as! ChecklistAddTagCell
cell.configCell()
cell.delegate = self
cell.tagNameLabel.text = tagsDictionary[indexPath.row + 1]?.name.capitalized
indexPathForBtn = indexPath
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
extension ChecklistAddTagVC: ChecklistAddTagCellDelegate{
// When the user press Add Tag then will be added in a dictionary and sent to ChecklistVC using a callback closure.
func addTagBtnPressed(button: UIButton, tagLabel: UILabel) {
let buttonPosition: CGPoint = button.convert(CGPoint.zero, to: tagsTableView)
let indexPath = tagsTableView.indexPathForRow(at: buttonPosition)
let indexPathForBtn: Int = indexPath?.row ?? 0
let tag: Tag = tagsDictionary[indexPathForBtn + 1] ?? Tag(remoteID: 0, categoryID: 0, name: String(), color: String())
if button.currentTitle == "+"{
button.setTitle("-", for: UIControl.State.normal)
tagLabel.textColor = UIColor.orange
// Add selected tag to Dictionary when the user press +
addedTags[tag.remoteID] = tag
}
else{
button.setTitle("+", for: UIControl.State.normal)
tagLabel.textColor = UIColor.black
// Delete selected tag from Dictionary when the user press -
addedTags.removeValue(forKey: tag.remoteID)
}
// Send the Dictionary to ChecklistVC
if delegate != nil{
delegate?.receiveAddedTags(tags: addedTags)
}
print("\n ****** UPDATED DICTIONARY ******")
print(addedTags.map {"key: \($1.remoteID) - name: \($1.name)"})
}
// Setup the state of the buttons and also the color of the buttons to be orange if that Tag exist in `addedTags` dictionary.
func setupButtons(){
for eachAddedTag in addedTags {
if eachAddedTag.value.remoteID == tagsDictionary[1]?.remoteID {
print(eachAddedTag)
}
}
}
}
And here is how looks now:
Can you try to handle tableview:didselectrowatindexpath instead of using the segue and on didselectrowatindexpath show the add tag vc.
I am trying to obtain the behaviour you find in whatsapp when trying to Add Participants to a group. In a tableView I have implemented UISearchController.
When a new row is selected in tableView, it is assigned an filled image(see screenshot below) and it is added/deleted to/from selectedUsers. When I start searching in the searchBar cells get rearranged and I get index out of range error, which is normal. I don't know where to go from here.
Scope:
allow the user to add/remove users whether searchBar is active or not
make sure there are no duplicate users in selectedUsers. This will be saved to DataBase.
remove cancel button that is attached on searchBar.
What have I tried?
class GroupRegistrationViewController: UITableViewController {
let searchController = UISearchController(searchResultsController: nil)
var usersArray = [User]() //users that currentUser is following
var currentUser: User!
var selectedUsers = [User]() //selected users in this controller, selected users we follow
var filteredUsers = [User]() //this property will hold the Users that the currentUser is searching for
override func viewDidLoad() {
super.viewDidLoad()
self.fetchUsers()
navigationItem.title = "GroupRegistration"
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.placeholder = "Search Members"
searchController.hidesNavigationBarDuringPresentation = false
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//simply check whether the user is searching or not
if isFiltering() {
return filteredUsers.count
}
return usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GroupRegistrationTableViewCell") as! GroupRegistrationTableViewCell
if isFiltering() {
cell.user = filteredUsers[indexPath.row]
}else{
cell.user = usersArray[indexPath.row]
}
if selectedUsers.contains(cell.user) {
//User type conforms to Equatable protocol so check is allowed
cell.added = true
}
return cell
}
//this method determines if you are currently filtering results or not
func isFiltering() -> Bool {
return searchController.isActive && !searchBarIsEmpty()
}
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! GroupRegistrationTableViewCell
cell.added = !cell.added
if cell.added == true {
self.addRecipient(user: cell.user)
}else{
let index = selectedUsers.index(of: cell.user)!
self.deleteRecipient(user: cell.user, index: index)
}
}
// - Helper methods
// - add
// - delete
func addRecipient(user: User) {
self.selectedUsers.append(user)
}
func deleteRecipient(user: User, index: Int) {
selectedUsers.remove(at: index)
}
}//end of class
extension GroupRegistrationViewController {
//get users from firebase
func fetchUsers() {
DatabaseReference.users(uid: currentUser.userUID).reference().child("follows").observe(.childAdded, with: { (snapshot) in
let user = User(dictionary: snapshot.value as! [String:Any])
self.usersArray.insert(user, at: 0)
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.insertRows(at: [indexPath], with: .fade)
})
}
}
//UISearchResultsUpdating Delegate
extension GroupRegistrationViewController: UISearchResultsUpdating {
func filteredContentForSearchText(searchText: String, scope: String = "All") {
filteredUsers = usersArray.filter({ (user) -> Bool in
return user.fullName.lowercased().contains(searchText.lowercased())
})
tableView.reloadData()
}
/*
whenever the user adds or removes text in the search bar, the UISearchController will inform the GroupRegistrationViewController class of the change via a call to updateSearchResults(for:), which in turn calls filterContentForSearchText(_:scope:).
*/
func updateSearchResults(for searchController: UISearchController) {
filteredContentForSearchText(searchText: searchController.searchBar.text!)
searchController.searchBar.showsCancelButton = false
//CancelButton shows up when I tap for the first time in the search bar. !!!! - not desired behaviour.
//CancelButton disapears when I start typing
}
}
`class GroupRegistrationTableViewCell: UITableViewCell {`
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var displayNameLabel: UILabel!
#IBOutlet weak var checkboxImageView: UIImageView!
#IBOutlet weak var fullNameTextLabel: UILabel!
var user: User! {
didSet {
self.updateUI()
}
}
//when a row is selected added property is assigned true/false value
var added: Bool = false {
didSet{
if added == false {
checkboxImageView.image = UIImage(named: "icon-checkbox")
}else {
checkboxImageView.image = UIImage(named: "icon-checkbox-filled")
}
}
}
//add cache here
var cache = SAMCache.shared()
func updateUI() {
let profilePictureKey = "\(user.userUID)-profilePicture"
if let image = cache?.image(forKey: profilePictureKey){
self.profileImageView.image = image
self.profileImageView.layer.cornerRadius = self.profileImageView.bounds.width / 2.0
self.profileImageView.layer.masksToBounds = true
} else {
user.downloadProfilePicture { (image, error) in
self.cache?.setImage(image, forKey: profilePictureKey)
self.profileImageView.image = image
self.profileImageView.layer.cornerRadius = self.profileImageView.bounds.width / 2.0
self.profileImageView.layer.masksToBounds = true
}
}
displayNameLabel.text = user.username
checkboxImageView.image = UIImage(named: "icon-checkbox")
fullNameTextLabel.text = user.fullName
}
`}//end of class`
I've searched for a solutions on this issue but none seem to work for my use case.
I have a table inside a viewcontroller and the issue I am facing is that when scrolling the UISwitch state is reset to OFF. I understand table cells are reused, but how do I implement a solution that will restore the state of UISwitch when a user scrolls based on my code below
import UIKit
class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var mylabel: UILabel!
var myString = String()
#IBAction func stirrBtn(_ sender: AnyObject) {
}
var timeSelected = String()
var selectedTimeArr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = myString
self.timeSelected = myString
}
func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
let kValue = (sender.tag + 1)
let keyValue = String(kValue)
if sender.isOn {
recipeSettings.boolStirrSwitch[keyValue] = true
recipeSettings.switchedOnArr.append(keyValue)
} else {
recipeSettings.boolStirrSwitch[keyValue] = false
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let stringNum = Int(self.timeSelected)
recipeSettings.recipeTimeSet2 = stringNum!
return(stringNum)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
// Process data displayed in rows(minutes)
let endTime = Int(self.timeSelected)
let startTime = Int(1)
// Recipe time array
let timeArray: [Int] = Array(startTime...endTime!)
let stringTimeArr = timeArray.map{String($0)}
// Save time array to global variable
recipeSettings.recipeTimeSetArr = stringTimeArr
// Create a boolean Array to hold all default false booleans
let defBool: Bool = false
var defBoolArr: [Bool] = []
// Fill the array with the defaults boolean
for _ in 0..<stringTimeArr.count{defBoolArr.append(defBool)}
// Map the array to global dictionary containing the Time in an array and default "false" value
for i in 0..<stringTimeArr.count {
recipeSettings.boolStirrSwitch[stringTimeArr[i]] = defBoolArr[i]
}
// Add the minutes to cell table
cell.textLabel?.text = stringTimeArr[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
As you can see in my code I do save the state of each UI switch in a global variable dictionary. How can I solve the issue of UISwitch changing states based on this code? All help is appreciated. Thanks in advance
var switchState = [String : Bool]()
your recipeSettings.boolStirrSwitch should be decleard like that.
As you are using timeSelected as numberOfRowsInSection as showing
your cell.textLabel from that so you don't need extra stringTimeArr
for that.
All the processing you do in cellForRowAt it will happen again and
again table cells are reused so for setting up data do it in another
function then reload TableView.
Solution for your problem should be look like that.
import UIKit
class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
//make tableView IBOutlet for reloading data
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var mylabel: UILabel!
var myString = String()
#IBAction func stirrBtn(_ sender: AnyObject) {
}
var timeSelected = String()
var selectedTimeArr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = myString
self.timeSelected = myString
self.setdefaultSwitchState()
}
//recipeSettings.boolStirrSwitch should be decleard like that
var switchState = [String : Bool]()
//setDeaultSwitchState
func setdefaultSwitchState(){
if let timeSelected = Int(self.timeSelected){
for value in 0..<timeSelected{
switchState["\(value)"] = false
//or
//recipeSettings.boolStirrSwitch["\(value)"] = false
}
}
self.tableView.reloadData()
}
#objc func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
let kValue = (sender.tag + 1)
let keyValue = String(kValue)
if sender.isOn {
switchState[keyValue] = true
} else {
switchState[keyValue] = false
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let stringNum = Int(self.timeSelected)
recipeSettings.recipeTimeSet2 = stringNum!
return(stringNum)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
cell.textLabel?.text = "\(indexPath.row + 1)"
if let switchState = switchState["\(indexPath.row)"] {
if switchState{
switchView.isOn = true
}else{
switchView.isOn = false
}
}else{
switchView.isOn = false
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Does somebody have a good Tutorial for a Search Bar with Sections? I did not found a good one yet. Or maybe you can help me straight with my project!?
The section Title is static but i integrated some customized subtitles to show the regions and the total time i spend to make all this Locations(Liegenschaften) in this section. I create this values in the function createWinterdienstDetail. This values should not change when i search for one Location.
I get the Values for my tableview from a different ViewController as
var AllWinterdienstTourInfos: [Int:[Int:[String]]] = [:] // Section - Locationnumber - Locationinformations
Here is my ViewController File:
import UIKit
class WinterdienstTourVC: UIViewController {
var sections = ["Tour 1","Tour 2","Tour 3","Tour 4"]
var LiegenschaftDetail: [String] = []
// VARIABLEN WINTERDIENST
var WinterdienstregionTour1: [String] = []
...
var WinterdienstregionTour15: [String] = []
var WinterdienstaufwandTour1String: [String] = []
...
var WinterdienstaufwandTour15String: [String] = []
var WinterdienstaufwandTour1: [Double] = []
...
var WinterdienstaufwandTour15: [Double] = []
var Totaltouraufwand1 = Double()
...
var Totaltouraufwand15 = Double()
var AllWinterdienstTourInfos: [Int:[Int:[String]]] = [:]
// Initialisierung
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
createWinterdienstDetail()
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView(frame: CGRect.zero)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "WinterdienstDetailSegue1") {
let DetailviewController = segue.destination as! WinterdienstLiegenschaftDetailVC
DetailviewController.LiegenschaftDetail = LiegenschaftDetail
}
}
func createWinterdienstDetail() {
if let liegenschaftenTour1 = AllWinterdienstTourInfos[0],
let liegenschaftenTour2 = AllWinterdienstTourInfos[1],
let liegenschaftenTour3 = AllWinterdienstTourInfos[2],
let liegenschaftenTour4 = AllWinterdienstTourInfos[3]{
self.myGroup.enter()
// DETAILS TOUR 1
for liegenschaften in liegenschaftenTour1.keys {
WinterdienstregionTour1.append(AllWinterdienstTourInfos[0]![liegenschaften]![6])
WinterdienstaufwandTour1String.append(AllWinterdienstTourInfos[0]![liegenschaften]![15])
for i in 0 ..< WinterdienstregionTour1.count-1 {
var j = WinterdienstregionTour1.count - 1
while(j > i) {
if WinterdienstregionTour1[i] == WinterdienstregionTour1[j] {
WinterdienstregionTour1.remove(at: j)
}
j -= 1
}
}
}
for WinterdienstaufwandTour1Array in WinterdienstaufwandTour1String {
WinterdienstaufwandTour1.append((WinterdienstaufwandTour1Array as NSString).doubleValue)
}
Totaltouraufwand1 = WinterdienstaufwandTour1.reduce(0,+)
// DETAILS TOUR 2
// DETAILS TOUR 3
// DETAILS TOUR 4
self.myGroup.leave()
self.myGroup.notify(queue: .main) {}
DispatchQueue.main.async {}
} // ENDE Function Create Winterdienst
} // ENDE CLASS WinterdienstTourVC
// DataSource-Methoden
extension WinterdienstTourVC: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int
{
return sections.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
// SECTION HEADER ALLGEMEIN
view.backgroundColor = UIColor.lightGray
// SECTION HEADER TOUR - NR
let tournr = UILabel()
tournr.text = sections[section]
tournr.font = UIFont.boldSystemFont(ofSize: 20.0)
tournr.frame = CGRect(x: 15,y:0, width: 100, height: 30)
view.addSubview(tournr)
// SECTION HEADER - TOURREGION / TOURAUFWAND
let tourregion = UILabel()
WinterdienstregionTour1.sort()
WinterdienstregionTour1.sort()
WinterdienstregionTour3.sort()
WinterdienstregionTour4.sort()
switch section{
case 0:
let tourregion1 = WinterdienstregionTour1.joined(separator: ", ")
tourregion.text = "\(tourregion1)"
case 1:
let tourregion2 = WinterdienstregionTour2.joined(separator: ", ")
tourregion.text = "\(tourregion2)"
.....
default:
tourregion.text = "Keine Angaben"
}
tourregion.font = UIFont.systemFont(ofSize: 16)
tourregion.frame = CGRect(x: 15,y:22, width: 200, height: 30)
view.addSubview(tourregion)
let touraufwand = UILabel()
switch section{
case 0:
touraufwand.text = "\(Totaltouraufwand1) h"
case 1:
touraufwand.text = "\(Totaltouraufwand2) h"
....
default:
touraufwand.text = "Keine Angaben"
}
touraufwand.frame = CGRect(x: -5,y:12, width: 370, height: 30)
touraufwand.font = UIFont.boldSystemFont(ofSize: 22.0)
touraufwand.textAlignment = .right
view.addSubview(touraufwand)
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int
{
switch section{
case 0:
return self.AllWinterdienstTourInfos[0]!.count
// self.WinterdienstadressTourAll[0]!.count
case 1:
return self.AllWinterdienstTourInfos[1]!.count
//self.WinterdienstAlltourinfosAll[1]![section]!.count
....
default:
return 1
}
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell
{
// versuchen, eine Zelle wiederzuverwenden
var cell = tableView.dequeueReusableCell(
withIdentifier: "cell")
if cell == nil {
// nicht möglich, daher neue Zelle erzeugen
cell = UITableViewCell(
style: .default, reuseIdentifier: "cell")
}
// Eigenschaften der Zelle einstellen
cell!.textLabel!.text = AllWinterdienstTourInfos[indexPath.section]![indexPath.row]?[4]
cell!.textLabel!.adjustsFontSizeToFitWidth = true
cell!.textLabel!.textAlignment = .left
// Zelle zurückgeben
return cell!
}
}
// TableView-Delegates
extension WinterdienstTourVC: UITableViewDelegate {
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath)
{
LiegenschaftDetail = AllWinterdienstTourInfos[indexPath.section]![indexPath.row]!
performSegue(withIdentifier: "WinterdienstDetailSegue1", sender: self)
}
}
i am new to ios swift 2.2 . I tried to create one table view with custom cell xib. and i am populating some data in my table view. And also i added one custom check box button. And i am creating separate class for that check box button. Now when i click only on my button in my customcell.xib .But when i tap on my cell, my check box are not changing. i need to have both. When i click on my button it should change to check and uncheck image. When i tap on my cell also i need to change my button to check or uncheck image
And when i scroll down and again come back to top, my checked images are automatically chnaged to normalcheck box.
i need to do some action , so for that. When i tap on any cell my check box should check and uncheck.And alos i need to know which row cell has checked image . So that i can perform some action for my checked image row cell alone.
here is my custom check box class:
import UIKit
class CheckBoxButton: UIButton {
// Images
let checkedImage = UIImage(named: "CheckBoxChecked")! as UIImage
let uncheckedImage = UIImage(named: "CheckBoxUnChecked")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, forState: .Normal)
} else {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: #selector(CheckBoxButton.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
if sender == self {
if isChecked == true {
isChecked = false
} else {
isChecked = true
}
}
}
}
Cutom cell.xib class:
import UIKit
class FavCell: UITableViewCell {
#IBOutlet weak var FLabel1: UILabel!
#IBOutlet weak var FLabel2: UILabel!
#IBOutlet weak var checkbox: CheckBoxButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func checkboxpress(sender: AnyObject) {
}
}
my viewcontroller.swift
import UIKit
class FavVC: UIViewController {
#IBOutlet weak var FavTableView: UITableView!
//var FData = [FavouritesData]()
var arrDict :NSMutableArray=[]
let cellSpacingHeight: CGFloat = 5 // cell spacing from each cell in table view
override func viewDidLoad() {
super.viewDidLoad()
self.jsonParsingFromURL()
let nib = UINib(nibName:"FavCell", bundle: nil)
FavTableView.registerNib(nib, forCellReuseIdentifier: "FCell")
}
// web services method
func jsonParsingFromURL ()
{
// let token = NSUserDefaults.standardUserDefaults().valueForKey("access_token") as? String
let url = NSURL(string: "som url")
let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: url!)
let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
// print("done, error: \(error)")
if error == nil
{
dispatch_async(dispatch_get_main_queue())
{
self.arrDict=(try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSMutableArray
if (self.arrDict.count>0)
{
self.FavTableView.reloadData()
}
}
}
}
dataTask.resume()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
// return self.FData.count
return self.arrDict.count
}
// number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
// height for each cell
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return cellSpacingHeight
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:FavCell = self.FavTableView.dequeueReusableCellWithIdentifier("FCell") as! FavCell
cell.FLabel1.text=arrDict[indexPath.section] .valueForKey("favourite_name") as? String
cell.FLabel2.text=arrDict[indexPath.section] .valueForKey("favourite_address") as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
please help me out.
Thanks in advance
In order to solve your issue, as #El Capitan mentioned, you will need to use the didSelectRowAtIndexPath method to change its states. Your codes should look something along the lines of this:
// Declare a variable which stores checked rows. UITableViewCell gets dequeued and restored as you scroll up and down, so it is best to store a reference of rows which has been checked
var rowsWhichAreChecked = [NSIndexPath]()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell:FavCell = tableView.cellForRowAtIndexPath(indexPath) as! FavCell
// cross checking for checked rows
if(rowsWhichAreChecked.contains(indexPath) == false){
cell.checkBox.isChecked = true
rowsWhichAreChecked.append(indexPath)
}else{
cell.checkBox.isChecked = false
// remove the indexPath from rowsWhichAreCheckedArray
if let checkedItemIndex = rowsWhichAreChecked.indexOf(indexPath){
rowsWhichAreChecked.removeAtIndex(checkedItemIndex)
}
}
}
To redisplay cells which have been checked before after scrolling the rows out of view, at your cellForRowAtIndexPath, perform the same checking against rowsWhichAreChecked array and set its states accordingly.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:FavCell = self.FavTableView.dequeueReusableCellWithIdentifier("FCell") as! FavCell
cell.FLabel1.text=arrDict[indexPath.section] .valueForKey("favourite_name") as? String
cell.FLabel2.text=arrDict[indexPath.section] .valueForKey("favourite_address") as? String
if(rowsWhichAreChecked.contains(indexPath) == false){
cell.checkBox.isChecked = true
}else{
cell.checkBox.isChecked = false
}
}
return cell
}
EDITED ANSWER
I have got your code to work but I had to make some modifications to your Checkbox class and ViewController
Checkbox.swift
class CheckBoxButton: UIButton {
// Images
let checkedImage = UIImage(named: "CheckBoxChecked")! as UIImage
let uncheckedImage = UIImage(named: "CheckBoxUnChecked")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(uncheckedImage, forState: .Normal)
} else {
self.setImage(checkedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.userInteractionEnabled = false
// self.addTarget(self, action: #selector(CheckBoxButton.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
// self.isChecked = false
}
func buttonClicked(sender: UIButton) {
if sender == self {
if isChecked == true {
isChecked = false
} else {
isChecked = true
}
}
}
}
ViewController.swift
class FavVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var FavTableView: UITableView!
var rowsWhichAreChecked = [NSIndexPath]()
//var FData = [FavouritesData]()
var arrDict :NSMutableArray=[]
let cellSpacingHeight: CGFloat = 5 // cell spacing from each cell in table view
override func viewDidLoad() {
self.FavTableView.delegate = self
self.FavTableView.dataSource = self
super.viewDidLoad()
self.jsonParsingFromURL()
let nib = UINib(nibName:"FavCell", bundle: nil)
FavTableView.registerNib(nib, forCellReuseIdentifier: "FCell")
}
// web services method
func jsonParsingFromURL ()
{
// let token = NSUserDefaults.standardUserDefaults().valueForKey("access_token") as? String
let url = NSURL(string: "some url")
let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: url!)
let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
// print("done, error: \(error)")
if error == nil
{
dispatch_async(dispatch_get_main_queue())
{
self.arrDict=(try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSMutableArray
if (self.arrDict.count>0)
{
self.FavTableView.reloadData()
}
}
}
}
dataTask.resume()
//
// let StringUrl = "http"+token!
// let url:NSURL = NSURL(string: StringUrl)!
// if let JSONData = NSData(contentsOfURL: url)
// {
// if let json = (try? NSJSONSerialization.JSONObjectWithData(JSONData, options: [])) as? NSDictionary
// {
// for values in json
// {
// self.FData.append()
// }
// if let reposArray = json["data"] as? [NSDictionary]
// {
//
// for item in reposArray
// {
// let itemObj = item as? Dictionary<String,AnyObject>
//
// let b_type = itemObj!["business_type"]?.valueForKey("type")
//
// //self.Resultcount.text = "\(b_type?.count) Results"
//
// if (b_type as? String == "Taxis")
// {
//
// self.FData.append(FavouritesData(json:item))
//
// }
// }
// }
// }
// }
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
// return self.FData.count
return self.arrDict.count
}
// number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
// height for each cell
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return cellSpacingHeight
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:FavCell = self.FavTableView.dequeueReusableCellWithIdentifier("FCell") as! FavCell
cell.FLabel1.text=arrDict[indexPath.section] .valueForKey("favourite_name") as? String
cell.FLabel2.text=arrDict[indexPath.section] .valueForKey("favourite_address") as? String
let isRowChecked = rowsWhichAreChecked.contains(indexPath)
if(isRowChecked == true)
{
cell.checkbox.isChecked = true
cell.checkbox.buttonClicked(cell.checkbox)
}else{
cell.checkbox.isChecked = false
cell.checkbox.buttonClicked(cell.checkbox)
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell:FavCell = tableView.cellForRowAtIndexPath(indexPath) as! FavCell
// cross checking for checked rows
if(rowsWhichAreChecked.contains(indexPath) == false){
cell.checkbox.isChecked = true
cell.checkbox.buttonClicked(cell.checkbox)
rowsWhichAreChecked.append(indexPath)
}else{
cell.checkbox.isChecked = false
cell.checkbox.buttonClicked(cell.checkbox)
// remove the indexPath from rowsWhichAreCheckedArray
if let checkedItemIndex = rowsWhichAreChecked.indexOf(indexPath){
rowsWhichAreChecked.removeAtIndex(checkedItemIndex)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
{
let cell:FilterTableViewCell = tableView.dequeueReusableCell(withIdentifier: "filtercell", for: indexPath) as! FilterTableViewCell
// Configure the cell...
cell.lblCategory?.attributedText = FontAttributes.sharedInstance.AttributesString(message: self.filterArray[indexPath.row], color: Textcolor)
cell.BtnIndex?.addTarget(self, action: #selector(checkMarkTapped(_ :)), for: .touchUpInside)
cell.BtnIndex?.tag = indexPath.row
let rowid = indexPath.row
let found = rowsWhichAreChecked.filter{$0.rowId == rowid}.count > 0
if found
{
cell.BtnIndex?.setImage(checkedImage, for: .normal)
}
else
{
cell.BtnIndex?.setImage(uncheckedImage, for: .normal)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell:FilterTableViewCell = tableView.cellForRow(at: indexPath) as! FilterTableViewCell
let rowid = indexPath.row
let found = rowsWhichAreChecked.filter{$0.rowId == rowid}.count > 0
if found
{
tempArrayFordelete = rowsWhichAreChecked
for obj in tempArrayFordelete
{
if let index = rowsWhichAreChecked.index(where: { $0.rowId == obj.rowId }) {
// removing item
rowsWhichAreChecked.remove(at: index)
cell.BtnIndex?.setImage(uncheckedImage, for: .normal)
}
}
}
else
{
cell.BtnIndex?.setImage(checkedImage, for: .normal)
let objrowId = selectedIndex(rowId: indexPath.row)
rowsWhichAreChecked.append(objrowId)
}
}
It gives me a great pleasure to inform you all that solve above issue
Resolving Issue Is
CheckBox Functionality
RadioButton Functionality
ReuseCell(tableView.dequeueReusableCell)//Also solve selected cell position issue.
Tested Code
Swift 5
iOS 12.2
Here is my code
import UIKit
class countrySelection:UITableViewCell{
#IBOutlet weak var imgFlag: UIImageView!
#IBOutlet weak var lblCountryName: UILabel!
#IBOutlet weak var btnSelection: UIButton!
}
class ViewController: UIViewController {
var listingDict=[[String:String]]()
var radioOption:Int?// Only used :: if u are 2. RadioButton Functionality implement
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource=self
tableView.delegate=self
fillCountryData()
// Do any additional setup after loading the view.
}
func fillCountryData(){
self.fillJsonData(imgName: "india_flag", countryName: "India")
self.fillJsonData(imgName: "pakistan_flag", countryName: "Pakistan")
self.fillJsonData(imgName: "israel_flag", countryName: "Israel")
self.fillJsonData(imgName: "albania_flag", countryName: "Albania")
self.fillJsonData(imgName: "america_flag", countryName: "America")
self.fillJsonData(imgName: "belize_flag", countryName: "Belize")
self.fillJsonData(imgName: "brunei_flag", countryName: "Brunei")
self.fillJsonData(imgName: "comoros_flag", countryName: "Comoros")
self.fillJsonData(imgName: "congo_flag", countryName: "Congo")
self.fillJsonData(imgName: "ecuador_flag", countryName: "Ecuador")
self.fillJsonData(imgName: "haiti_flag", countryName: "Haiti")
self.fillJsonData(imgName: "jamaica_flag", countryName: "Jamaica")
self.fillJsonData(imgName: "kenya_flag", countryName: "Kenya")
self.fillJsonData(imgName: "mali_flag", countryName: "Mali")
self.tableView.reloadData()
}
func fillJsonData(imgName:String,countryName:String){
var dictData=[String:String]()
dictData["img"]=imgName
dictData["country"]=countryName
dictData["check"]="false"
listingDict.append(dictData)
}
}
extension ViewController:UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listingDict.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "countrySelection") as! countrySelection
let dictVal=listingDict[indexPath.row]
cell.lblCountryName.text=dictVal["country"]
cell.imgFlag.image=UIImage(named:dictVal["img"]!)
/*//Check Box Functionality
if dictVal["check"] == "false"{
cell.btnSelection.setImage(UIImage(named: "checkbox_UnSelect"), for: .normal)
} else{
cell.btnSelection.setImage(UIImage(named: "checkbox_Select"), for: .normal)
}*/
//RadioButton Functionality
if radioOption==indexPath.row{
listingDict[indexPath.row]["check"]="true"
cell.btnSelection.setImage(UIImage(named: "radioButton_Select"), for: .normal)
} else{
listingDict[indexPath.row]["check"]="false"
cell.btnSelection.setImage(UIImage(named: "radioButton_UnSelect"), for: .normal)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
/*//CheckBox Functionality
if listingDict[indexPath.row]["check"]=="true"{
listingDict[indexPath.row]["check"]="false"
} else{
listingDict[indexPath.row]["check"]="true"
}*/
//RadioButton Functionality
print("RadioButton",listingDict)
if listingDict[indexPath.row]["check"]=="true"{
radioOption=nil
} else{
radioOption=indexPath.row
}
self.tableView.reloadData()
}
}