Custom delegate method is calling - swift

import UIKit
protocol CustomCellDelegate: class {
func liked(dataDict:NSDictionary,index:NSInteger)
}
class NameImageTextCell: UITableViewCell,UIActionSheetDelegate {
weak var delegateCell: CustomCellDelegate?
#IBAction func btnAction(_ sender: UIButton) {
if delegateCell==nil{
delegateCell?.liked(dataDict: dataNodeDict, index: ItemIndex)
}
}
}
////////
class
FanWallVC:UIViewController,UITableViewDelegate,UITableViewDataSource,
CustomCellDelegate {
#IBOutlet weak var tableView: UITableView!
let objNameImageTextCell = NameImageTextCell()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "NameImageTextCell", bundle: nil),
forCellReuseIdentifier: "NameImageTextCell")
objNameImageTextCell.delegateCell=self
}
func liked(dataDict: NSDictionary, index: NSInteger) {
print("Called")
}
}
When i Click on IBAction(btnAction) in NameImageTextCell, delegateCell is nil,
So liked method is not getting call.
Please help me.
Thanks in advance

You probably should call:
objNameImageTextCell.delegateCell = self
in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
so it should look somthing like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NameImageTextCell", for: indexPath) as! NameImageTextCell
cell.delegateCell = self
//other cell customization
return cell
}

Related

How to pass selected data from a PopUpTableViewController to other TableViewController in Swift?

I have 2 View Controllers: In the first ViewController that has a TableView, I have a button in each TableViewCell to select a shipping option. When clicking the button, another TableViewController will pop up with a list of shipping options. Upon choosing a shipping option, I need to pass this data back to TableViewCell in the first ViewController. I wrote below code but the shipping option selected in the second TableViewController still didn't pass to the first controller. Other things work fine. Could anyone help to let me know how to improve this code? Thanks a million!
//First ViewController:
class PaymentMethodViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//MARK: - IBOutlets
#IBOutlet weak var PurchasedReviewItemsTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PurchasedReviewItemsTableViewCell") as! PurchasedReviewItemsTableViewCell
cell.delegate = self
}
}
extension PaymentMethodViewController: PurchasedReviewItemsTableViewCellDelegate {
func chooseShippingOptionButtonPressed() {
let chooseShippingOptionVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(identifier: "ShippingOptionsSelectionPopUpViewController") as! ShippingOptionsSelectionPopUpViewController
chooseShippingOptionVC.modalPresentationStyle = .overCurrentContext
self.present(chooseShippingOptionVC, animated: true, completion: nil)
}
//MARK: Pass data from popUpView
func popUpShippingOptionsSelected(shippingOption: String) {
let cell = PurchasedReviewItemsTableView.dequeueReusableCell(withIdentifier: "PurchasedReviewItemsTableViewCell") as! PurchasedReviewItemsTableViewCell
cell.shippingOptionsLabel.text = shippingOption
}
}
//TableViewCell of the first ViewController:
protocol PurchasedReviewItemsTableViewCellDelegate {
func chooseShippingOptionButtonPressed()
func popUpShippingOptionsSelected(shippingOption: String)
}
class PurchasedReviewItemsTableViewCell: UITableViewCell {
#IBOutlet weak var shippingOptionsLabel: UILabel!
var delegate: PurchasedReviewItemsTableViewCellDelegate?
#IBAction func changeShippingOptionButtonPressed(_ sender: Any) {
delegate?.chooseShippingOptionButtonPressed()
}
}
//Second TableViewController:
class ShippingOptionsSelectionPopUpViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var selectedShippingOption : String?
var shippingOption = ["X", "Y"]
var delegate: ShippingOptionsSelectionPopUpDelegate?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ShippingOptionsSelectionPopUpTableViewCell", for: indexPath) as! ShippingOptionsSelectionPopUpTableViewCell
cell.selectShippingOption(shippingOption: shippingOption[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedShippingOption = shippingOption[indexPath.row]
delegate?.popUpShippingOptionsSelected(shippingOption: selectedShippingOption!)
dismiss(animated: true, completion: nil)
}
}
Define separate protocol for popUpShippingOptionsSelected
protocol ShippingOptionsDelegate {
func popUpShippingOptionsSelected(shippingOption: String)
}
class ShippingOptionsSelectionPopUpViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var selectedShippingOption : String?
var shippingOption = ["X", "Y"]
var shippingOptiondelegate: ShippingOptionsSelectionPopUpDelegate?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ShippingOptionsSelectionPopUpTableViewCell", for: indexPath) as! ShippingOptionsSelectionPopUpTableViewCell
cell.selectShippingOption(shippingOption: shippingOption[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedShippingOption = shippingOption[indexPath.row]
shippingOptiondelegate?.popUpShippingOptionsSelected(shippingOption: selectedShippingOption!)
dismiss(animated: true, completion: nil)
}
}
Add tag to cell
class PaymentMethodViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//MARK: - IBOutlets
#IBOutlet weak var PurchasedReviewItemsTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PurchasedReviewItemsTableViewCell") as! PurchasedReviewItemsTableViewCell
cell.delegate = self
cell.tag = 100 // Set tag
}
}
Update extension with ShippingOptionsDelegate
extension PaymentMethodViewController: PurchasedReviewItemsTableViewCellDelegate, ShippingOptionsDelegate {
func chooseShippingOptionButtonPressed() {
let chooseShippingOptionVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(identifier: "ShippingOptionsSelectionPopUpViewController") as! ShippingOptionsSelectionPopUpViewController
chooseShippingOptionVC.shippingOptiondelegate = self
chooseShippingOptionVC.modalPresentationStyle = .overCurrentContext
self.present(chooseShippingOptionVC, animated: true, completion: nil)
}
//MARK: Pass data from popUpView
func popUpShippingOptionsSelected(shippingOption: String) {
let cell = PurchasedReviewItemsTableView.viewWithTag(100) as! PurchasedReviewItemsTableViewCell // use tag to get cell
cell.shippingOptionsLabel.text = shippingOption
}
}

UISwitches in UITableViewCell change states together

I have a very strange problem in my Swift project. I use UIswitch in my dynamic cells in my one-section uitable. Whenever I click on the 6th switch, the first one changes its state with it and vice versa. The .valueChanged function only works for the one that is clicked (correct behaviour).
I cannot figure out why the switches change state together.
This is the code for table cells:
import UIKit
class RoutineTableViewCell: UITableViewCell {
#IBOutlet weak var selectionSwitch: UISwitch!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var previewImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
and here is the code in my table view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RoutineTableReuseIdentifier, for: indexPath) as? RoutineTableViewCell
else{
return RoutineTableViewCell()
}
let exercise = section!.exercises[indexPath.row]
cell.title.text = exercise.title
cell.previewImage.image = UIImage(named: (exercise.gifName + ".gif"))
cell.selectionSwitch.addTarget(self, action: #selector(self.addRemoveExercise(_:)), for: .valueChanged)
return cell
}
#IBAction func addRemoveExercise(_ sender: UISwitch!) {
let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
if(sender.isOn){
customizedSection?.exercises[indexPath!.row] = section!.exercises[indexPath!.row]
}
else{
customizedSection?.exercises[indexPath!.row] = ExerciseModel()
}
}
Your tableView:
import UIKit
class TableViewController: UITableViewController,switchValues {
func changed(_ cell: UITableViewCell, _ mySwitch: UISwitch) {
let index = tableView.indexPath(for: cell)
switchStates[(index?.row)!] = mySwitch.isOn
tableView.reloadData()
}
var switchStates : [Bool] = [false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return switchStates.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.mySwitch.isOn = switchStates[indexPath.row]
cell.delegate = self
return cell
}
Your cell:
import UIKit
protocol switchValues {
func changed(_ cell:UITableViewCell,_ mySwitch:UISwitch)
}
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var mySwitch: UISwitch!
var delegate:switchValues!
#IBAction func valueChanged(_ sender: UISwitch) {
delegate.changed(self, mySwitch)
}
}

Swift UiTableView not reloading search results

I am having a weird issue where for some reason my UITableView is not being reloading after performing a search. The console prints out the correctly filtered data, but the table simply doesn't change. I have never encountered this issue, so I first attempted the solutions which naturally came to mind:
Tried tableView.reloadData() in the Main Queue
Quit Xcode, clean build, reinstall
Cleared out the derived data dir
I have found several similar issue in SO, but all of the solutions I've seen are things I've tried, mainly reloading tableview in main queue.
Hoping maybe I just simply have an issue in my code or something I'm missing.
I am running Xcode 8.3.3
import UIKit
class CategoriesViewController: UIViewController {
var isFiltering = false
var location = Location()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var categoriesSearchResults = [Category]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.allowsSelection = true
tableView.keyboardDismissMode = .onDrag
let nib = UINib(nibName: "CategoryTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier:"CategoryTableViewCell");
searchBar.returnKeyType = UIReturnKeyType.done
searchBar.autocapitalizationType = .none
searchBar.delegate = self
}
extension CategoriesViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("HI")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering {
return self.categoriesSearchResults.count
}
return self.location.categories.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
}
return cell
}
}
extension CategoriesViewController : UISearchBarDelegate {
func searchBarIsEmpty() -> Bool{
return self.searchBar.text?.isEmpty ?? true
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.isFiltering = true
self.categoriesSearchResults.removeAll()
tableView.reloadData()
self.view.endEditing(true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBarIsEmpty() {
self.view.endEditing(true)
self.isFiltering = false
} else {
self.isFiltering = true
self.categoriesSearchResults = self.location.categories.filter({ (category: Category) -> Bool in
return category.name.lowercased().contains(searchText.lowercased())
})
}
tableView.reloadData()
}
}
and my custom table view cell:
import UIKit
class CategoryTableViewCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var status: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func prepareForReuse() {
super.prepareForReuse()
self.name.text = ""
self.status.text = ""
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Thank you in advance.
EDIT: Might also be worth mentioning, when I am actively searching, the function tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) is not called??
The scope of if let nests in its scope. In your code you are always returning let cell = UITableViewCell(). Try returning it inside the if let :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell {
var category: Category
if isFiltering {
category = self.categoriesSearchResults[indexPath.row]
} else {
category = self.location.categories[indexPath.row]
}
cell.name.text = category.name
cell.status.textColor = UIColor.lightGray
cell.status.text = "Not Verified"
/// RETURN CELL HERE
return cell
}
return cell
}

Unable to segue tableview

I am trying to create a Tableview app and here is my code, I am unable to segue due to an error saying cvc.college = colleges[indexPath.row] saying cannot assign value of type 'string' to 'College!'
What do i do?
import UIKit
class ViewController: UIViewController, UITableViewDelegate ,UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
var colleges = ["Harper","UofI","Florida State University"]
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
var college1 = College(name: "Harper", state: "IL", population: "25,000+")
var college2 = College(name: "UofI", state: "IL", population: "44,000+")
var college3 = College(name: "Florida State University", state: "Fl", population:"40,000+")
var colleges = [college1 , college2, college3]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return colleges.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = myTableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
myCell.textLabel!.text = colleges[indexPath.row]
return myCell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if editingStyle == .delete {
colleges.remove(at: indexPath.row)
tableView.reloadData()
let college = colleges[indexPath.row]
}
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let college = colleges[sourceIndexPath.row ]
colleges.remove(at: sourceIndexPath.row)
colleges.insert(college, at: destinationIndexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var cvc = segue.destination as! CollegeViewController
if let cell = sender as? UITableViewCell,
let indexPath = self.myTableView.indexPath(for: cell) {
cvc.college = colleges[indexPath.row]
}
}
heres my code for CollegeViewController
class CollegeViewController: UIViewController {
var college : College!
#IBAction func onTappedSave(_ sender: UIButton) {
college.name = collegeText.text!
college.state = stateText.text!
college.population = populationText.text!
}
#IBOutlet weak var collegeText: UITextField!
#IBOutlet weak var populationText: UITextField!
#IBOutlet weak var stateText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
collegeText.text = college.name
stateText.text = college.state
populationText.text = String(college.population)
}
}
First of all you need to put moveRowAt and prepareForSegue methods inside the ViewController class because currently you have added it as outside the class.
After that your prepareForSegue like this.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var cvc = segue.destination as! CollegeViewController
if let cell = sender as? UITableViewCell,
let indexPath = self.myTableView.indexPath(for: cell) {
cvc.college = colleges[indexPath.row]
}
}
Whole code would be like this.
import UIKit
class ViewController: UIViewController, UITableViewDelegate ,UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
var colleges = ["Harper","UofI","Florida State University"]
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return colleges.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = myTableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
myCell.textLabel!.text = colleges[indexPath.row]
return myCell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if editingStyle == .delete {
colleges.remove(at: indexPath.row)
tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let college = colleges[sourceIndexPath.row ]
colleges.remove(at: sourceIndexPath.row)
colleges.insert(college, at: destinationIndexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var cvc = segue.destination as! CollegeViewController
if let cell = sender as? UITableViewCell,
let indexPath = self.myTableView.indexPath(for: cell) {
cvc.college = colleges[indexPath.row]
}
}
}
Note: There is no code of self.performSegue, so I'm considering that you have created segue from UITableViewCell to CollegeViewController.

Swift MapKit Autocomplete

I am trying to set an address autocomplete in my view controller so users do not have to type the whole address and instead select it from below the search textfield. This is how my controller looks like:
import Foundation
import UIKit
import MapKit
extension AddNewAddressViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
}
}
class AddNewAddressViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var searchCompleter = MKLocalSearchCompleter()
var searchResults = [MKLocalSearchCompletion]()
override func viewDidLoad() {
searchCompleter.delegate = self
searchCompleter.queryFragment = addressSearch.text!
searchResultsTableView.dataSource = self
super.viewDidLoad()
}
#IBOutlet weak var addressSearch: UITextField!
#IBOutlet weak var searchResultsTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let searchResultsCount = searchResults.count
return searchResultsCount
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let searchResult = searchResults[indexPath.row]
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.text = searchResult.title
cell.detailTextLabel?.text = searchResult.subtitle
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
#IBAction func defaultAddressButton(_ sender: Any) {
}
#IBAction func addAddressButton(_ sender: Any) {
}
}
I am getting an error that says:
Type AddNewAddressViewController does not conform to protocol 'UITableViewDataSource'
What am I missing?
Thanks in advance.
You left out the underscore for first parameter of the cellForRowAtIndexPath declaration, which is required under swift 3.0:
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
[etc.]
As a result, you don't have a required function matching the expected signature.