Swift MapKit Autocomplete - swift

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.

Related

Cannot assign value of type 'String' to type 'UILabel'

I am trying to pass data from tableview to another page (view controller) but problem is i am getting an error from tableview. Below is the code and i have marked the error where i am getting.
P1ViewController.Swift
class P1ViewController: ViewController,UITableViewDelegate,UITableViewDataSource {
var name=["Table1","Table2"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return name.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text=name[indexPath.row]
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let detail=self.storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
detail.lblName=name[indexPath.row] //This is the error i am getting "Cannot assign value of type 'String' to type 'UILabel'"
self.navigationController?.pushViewController(detail, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
DetailViewController.Swift
class DetailViewController: ViewController {
#IBOutlet weak var lblName: UILabel!
var name:String!
override func viewDidLoad() {
super.viewDidLoad()
lblName.text=name
}
}
Actually you would have to write
detail.lblName.text = name[indexPath.row]
but this will cause a crash. Assign the value to the name property
detail.name = name[indexPath.row]

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 3.0 Autocomplete Address For Search Bar

I am interested in using a tableView to list possible addresses based on inputs in the search bar. After selecting the cell that contains the address desired, the search bar text consists of the address, however I want the possible addresses (cells) to disappear. Does self.searchResultsTableView.reloadData() in didSelectRowAt clear all the cells or is there another command? I am not certain how to clear the cells after selecting the appropriate address without iterating and having the suggestion introduce more cells.
import UIKit
import MapKit
class SearchViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
var searchCompleter = MKLocalSearchCompleter()
var searchResults = [MKLocalSearchCompletion]()
var searchSource: [String]?
#IBOutlet weak var searchResultsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
searchCompleter.delegate = self
searchBar.delegate = self
}
}
extension SearchViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchCompleter.queryFragment = searchText
}
}
extension SearchViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
}
}
extension SearchViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 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
}
}
extension SearchViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let completion = searchResults[indexPath.row]
let searchRequest = MKLocalSearchRequest(completion: completion)
let search = MKLocalSearch(request: searchRequest)
search.start { (response, error) in
let coordinate = response?.mapItems[0].placemark.coordinate
print(String(describing: coordinate))
print(response?.mapItems)
self.searchBar.text = response?.mapItems[0].name
}
self.searchResultsTableView.reloadData()
}
}
If you want to clear your tableView then you need to make your datasource array empty and then reload the tableView.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let completion = searchResults[indexPath.row]
let searchRequest = MKLocalSearchRequest(completion: completion)
let search = MKLocalSearch(request: searchRequest)
search.start { (response, error) in
let coordinate = response?.mapItems[0].placemark.coordinate
print(String(describing: coordinate))
print(response?.mapItems)
self.searchBar.text = response?.mapItems[0].name
}
//Make empty your array ant then reload tableView
searchResults = []
self.searchResultsTableView.reloadData()
}

Custom delegate method is calling

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
}

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.