searchBar created from StoryBoard doesn't connect with UISearchController - uitableview

I created a searchBar programmatically which is connected to a UITableViewController
let locationSearchTable = storyboard!.instantiateViewController(withIdentifier:
"LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController:
locationSearchTable)
resultSearchController.searchResultsUpdater = locationSearchTable
let searchBar = resultSearchController.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for places"
navigationItem.titleView = resultSearchController.searchBar
resultSearchController.searchBar.delegate = self
resultSearchController.hidesNavigationBarDuringPresentation = false
resultSearchController.obscuresBackgroundDuringPresentation = true
definesPresentationContext = true
locationSearchTable.mapView = mapView
locationSearchTable.handleMapSearchDelegate = self
It works perfectly. But when i try to assign searchBar to my SearchBars created from storyBoard they don't work. I did delegate connection from storyboard as well.
class MapViewController: UIViewController, UISearchBarDelegate,
UITableViewDelegate {
#IBOutlet weak var myFrom: UISearchBar!
#IBOutlet weak var myTo: UISearchBar!
....
override func viewDidLoad() {
...
myFrom = resultSearchController.searchBar
myTo = resultSearchController.searchBar
myFrom.delegate = self
myTo.delegate = self
I also need tableview results to have same width as searchBar in the pop-up view. Not entire screen width as programmatically created.
I use the subLocality data in the searchBars. For now, I just pull data from MKPlacemarks into searchBars.
I couldn't activate the searchBars.
TableView code:
import Foundation
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var handleMapSearchDelegate: HandleMapSearch? = nil
var mapView: MKMapView? = nil
var searchResults = [MKLocalSearchCompletion]()
private var boundingRegion: MKCoordinateRegion = MKCoordinateRegion(MKMapRect.world)
lazy var searchCompleter: MKLocalSearchCompleter = {
let sC = MKLocalSearchCompleter()
sC.delegate = self
sC.resultTypes = .pointOfInterest
sC.region = boundingRegion
return sC
}()
private var places: [MKMapItem]? {
didSet {
tableView.reloadData()
}
}
private var localSearch: MKLocalSearch? {
willSet {
// Clear the results and cancel the currently running local search before starting a new search.
places = nil
localSearch?.cancel()
}
}
/// - Parameter suggestedCompletion: A search completion provided by `MKLocalSearchCompleter` when tapping on a search completion table row
private func search(for suggestedCompletion: MKLocalSearchCompletion) {
let searchRequest = MKLocalSearch.Request(completion: suggestedCompletion)
search(using: searchRequest)
}
/// - Tag: SearchRequest
private func search(using searchRequest: MKLocalSearch.Request) {
// Confine the map search area to an area around the user's current location.
searchRequest.region = boundingRegion
localSearch = MKLocalSearch(request: searchRequest)
localSearch?.start { [unowned self] (response, error) in
guard error == nil else {
self.displaySearchError(error)
return
}
self.places = response?.mapItems
// Used when setting the map's region in `prepareForSegue`.
if let updatedRegion = response?.boundingRegion {
self.boundingRegion = updatedRegion
}
}
}
private func displaySearchError(_ error: Error?) {
if let error = error as NSError?, let errorString = error.userInfo[NSLocalizedDescriptionKey] as? String {
let alertController = UIAlertController(title: "Could not find any places.", message: errorString, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController, animated: true, completion: nil)
}
}
}
extension LocationSearchTable: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController)
{
searchCompleter.queryFragment = searchController.searchBar.text ?? ""
self.tableView.reloadData()
}
}
extension LocationSearchTable: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
self.tableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
print("error loading MKLocalSearchCompleter")
}
}
//- Tableview DataSource methods
extension LocationSearchTable {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
override 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
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedItem = searchResults[indexPath.row]
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = selectedItem.title
let search = MKLocalSearch(request: request)
search.start { (response, error) in
guard let response = response else {return}
guard let item = response.mapItems.first else {return}
self.handleMapSearchDelegate?.dropPinZoomIn(placemark: item.placemark)
self.dismiss(animated: true, completion: nil)
}
}
}
programmatically created SearchBar
StoryBoard SearchBars

Related

Sending selected URLS with SMTP (Swift)

I have tableview listed pdfs by retrieving from Firebase. No problem with retrieving datas and sending default SMTP. What I am trying to do that selected urls(pdf) in tableview, will be sent by using SMTP to user email so that user can easily reach pdf urls. I could not figure out how to handle it. This is the only critical point in my project. Any help is appreciated.
import UIKit
import Firebase
import PDFKit
import skpsmtpmessage
class IcsViewcontroller: UIViewController , UISearchBarDelegate,SKPSMTPMessageDelegate{
var preImage : UIImage?
let cellSpacingHeight: CGFloat = 20
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var pdfListView: UITableView!
#IBOutlet weak var spinner: UIActivityIndicatorView!
var pdfList = [pdfClass]()
var searchall = [pdfClass]()
var searching = false
var selectedPdf = [pdfClass]()
override func viewDidLoad() {
super.viewDidLoad()
let editButton = UIBarButtonItem(title: "Edit", style: .plain, target: self, action: #selector(showEditing(_:)))
navigationItem.rightBarButtonItem = editButton
pdfListView.delegate = self
pdfListView.dataSource = self
searchBar.delegate = self
self.pdfListView.isHidden = true
getPdf()
sendEmail()
searchBar.searchTextField.backgroundColor = .white
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let selectionIndexPath = self.pdfListView.indexPathForSelectedRow {
self.pdfListView.deselectRow(at: selectionIndexPath, animated: animated)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if searching {
let destination = segue.destination as! PdfKitViewController
let selectedIndexPath = pdfListView.indexPathForSelectedRow
destination.pdf = searchall[selectedIndexPath!.row]
} else {
let destination = segue.destination as! PdfKitViewController
let selectedIndexPath = pdfListView.indexPathForSelectedRow
destination.pdf = pdfList [selectedIndexPath!.row]
}
}
#objc func showEditing(_ sender: UIBarButtonItem)
{
if(self.pdfListView.isEditing == true)
{
self.pdfListView.isEditing = false
self.navigationItem.rightBarButtonItem?.title = "Edit"
}
else
{
self.pdfListView.allowsMultipleSelectionDuringEditing = true
self.pdfListView.isEditing = true
self.navigationItem.rightBarButtonItem?.title = "Done"
}
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
if searchBar.text == nil || searchBar.text == "" {
searching = false
} else {
searching = true
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
self.pdfListView.reloadData()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searching = false
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
searchall = pdfList
searching = false
pdfListView.reloadData()
} else {
searching = true
searchall = pdfList.filter({($0.pdf_name?.lowercased().prefix(searchText.count))! == searchText.lowercased() })
pdfListView.reloadData()
}
}
func getPdf () {
spinner.startAnimating()
let docRef = Storage.storage().reference().child("ICS_Documents")
docRef.listAll{ (result , error ) in
if error != nil {
let alert = UIAlertController(title: "Error", message: "No Database Connection", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
self.spinner.stopAnimating()
}
for item in result.items {
let storeageLocation = String( describing : item)
let gsReference = Storage.storage().reference(forURL: storeageLocation)
gsReference.downloadURL{ url , error in
if let error = error{
print(error)
} else {
let pdf_name = String( item.name)
let pdf_url = url?.absoluteString
let thumbnailSize = CGSize(width: 100, height: 100)
let thmbnail = self.generatePdfThumbnail(of: thumbnailSize, for: url!, atPage: 0)
let pdfall = pdfClass(pdf_name: pdf_name, pdf_url: pdf_url!, pdf_preview: thmbnail!)
self.pdfList.append(pdfall)
}
DispatchQueue.main.async {
self.pdfList.sort{ $0.pdf_name ?? "" < $1.pdf_name ?? ""}
self.pdfListView.reloadData()
self.spinner.stopAnimating()
self.pdfListView.isHidden = false
}
}
}
}
}
func generatePdfThumbnail(of thumbnailSize: CGSize , for documentUrl: URL, atPage
pageIndex: Int) -> UIImage? {
let pdfDocument = PDFDocument(url: documentUrl)
let pdfDocumentPage = pdfDocument?.page(at: pageIndex)
return pdfDocumentPage?.thumbnail(of: thumbnailSize, for:
PDFDisplayBox.trimBox)
}
func sendEmail() {
let message = SKPSMTPMessage()
message.relayHost = "smtp.gmail.com"
message.login = "xxx#gmail.com"
message.pass = "******"
message.requiresAuth = true
message.wantsSecure = true
message.relayPorts = [587]
message.fromEmail = "xxxx#gmail.com"
message.toEmail = "xxxx#gmail.com"
message.subject = "subject"
let messagePart = [kSKPSMTPPartContentTypeKey: "text/plain; charset=UTF-8",
kSKPSMTPPartMessageKey: "Hi alll"]
message.parts = [messagePart]
message.delegate = self
message.send()
}
func messageSent(_ message: SKPSMTPMessage!) {
print("Successfully sent email!")
}
func messageFailed(_ message: SKPSMTPMessage!, error: Error!) {
print("Sending email failed!")
}
}
extension IcsViewcontroller : UITableViewDelegate,UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if searching{
return searchall.count
}else {
return pdfList.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "pdfCell", for: indexPath) as! pdfCellTableViewCell
let varcell : pdfClass
if searching {
varcell = searchall [indexPath.row]
} else {
varcell = pdfList [indexPath.row]
}
cell.configure(name: varcell.pdf_name! , pdfthumbnail: varcell.pdf_preview!)
cell.accessoryType = .disclosureIndicator
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var indx : pdfClass
if searching{
indx = searchall[indexPath.row ]
}else {
indx = pdfList[indexPath.row]
}
self.selectdeselectcell(tableview: tableView, indexpath: indexPath)
print("selected")
if pdfListView.isEditing {
func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
return !tableView.isEditing
}
}else{
performSegue(withIdentifier: "toPdfKit", sender: indx)
print(indexPath.row)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.selectdeselectcell(tableview: tableView, indexpath: indexPath)
print("deselected")
}
func selectdeselectcell(tableview : UITableView ,indexpath : IndexPath){
if pdfListView.isEditing{
self.selectedPdf.removeAll()
if let arr = pdfListView.indexPathForSelectedRow{
print(arr)
}
}else {
return
}
}
/* func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .default, title: "Delete", handler: { (action:UITableViewRowAction,indexPath:IndexPath)-> Void in
let storage = Storage.storage()
var childsURL : String
if self.searching {
childsURL = self.searchall[indexPath.row ].pdf_url!
}else{
childsURL = self.pdfList[indexPath.row].pdf_url!
}
let storageref = storage.reference(forURL: childsURL)
storageref.delete{ error in
if let error = error {
print(error.localizedDescription)
} else{
print("File deleted")
}
}
self.pdfList.removeAll()
self.getPdf()
})
return [deleteAction]
}*/
}

populate fetched data to tableView using UISearchController

I am fetching data from an API and works fine when i type in a city in console. The problem i am facing now is with UISearchController and tableView in the code below i want to populate my searched city in the tableView. Now it does not show up anything when i run the app, except in my console that logs my request when a searched in the searchbar
LOG:
Search text: London
Creating request..
Task started
City name: London
Success! JSON decoded
this means using the searchfunction with the APIrequest works, except that i cant see it in my tableView
here is my viewController
import UIKit
class ViewController: UIViewController{
#IBOutlet weak var tblView: UITableView!
let mWeather = WeatherAPI()
var weatherArray = [WeatherStruct]()
var filteredWeatherArray : [String] = []
// dummy data
let originalArray = ["gothenburg", "london", "stockholm", "new york", "washington DC", "thailand", "china", "spain", "paris"]
var searching: Bool {
if weatherArray.count > 0 {
return true
} else {
return false
}
}
let searchController: UISearchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "type in your city here"
navigationItem.searchController = searchController
tblView.delegate = self
tblView.dataSource = self
}
}
// MARK: - extensions
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text ?? "can not search"
print("Search text: \(searchText)")
mWeather.fetchCurrentWeather(city: searchText) { (WeatherStruct) in}
tblView.reloadData()
}
}
// MARK: - Table view data source
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return weatherArray.count // when something is typed on searchbar
}else{
return filteredWeatherArray.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell", for: indexPath)
if searching {
cell.textLabel?.text = weatherArray[indexPath.row].name
tblView.reloadData()
} else {
cell.textLabel?.text = filteredWeatherArray[indexPath.row]
tblView.reloadData()
}
return cell
}
}
EDIT: as this maybe can help someone to help me = API request handler
func fetchCurrentWeather(city: String, completionHandler: #escaping (WeatherStruct) -> Void) {
// url
let wholeUrl = baseUrlForCurrentWeather + city + appid + metric
let urlString = (wholeUrl)
guard let url: URL = URL(string: urlString) else { return }
// Request
print("Creating request..")
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let unwrappedError = error {
print("Nått gick fel. Error: \(unwrappedError)")
return
}
if let unwrappedData = data {
do {
let decoder = JSONDecoder()
let wdata: WeatherStruct = try decoder.decode(WeatherStruct.self, from: unwrappedData)
print("City name: \(String(describing: wdata.name))")
print("Success! JSON decoded")
completionHandler(wdata)
} catch {
print("Couldnt parse JSON..")
print(error)
}
}
}
// Starta task
task.resume()
print("Task started")
}
You need to update the filteredWeatherArray from the result you are getting from fetchCurrentWeather in your updateSearchResults(for searchController method, here's how:
mWeather.fetchCurrentWeather(city: searchText) { weather in
self.weatherArray = [weather]
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Edit: Even though the above code might work for you, you might not get the desired result. You are trying to display a list from the array of weatherArray, but when you make a call to fetchCurrentWeather you are getting just one result. I have modified my code to set the one array element to set as the weatherArray and reload.

How to fix a UITableView class which repeat twice elements read on Firebase database and in the load the table is empty?

I'm trying to read from firebase realtime database a series of instructions.
I have an unknown number of information on my Vehicles node, so I just use nextObject method to get the number of times that the function need to iterate.
The problem is that at the opening, my table is empty. When I click on the searchbar then my cells contents did appear. How can I solve these problem?
Here my UITableView file:
import UIKit
import FirebaseDatabase
import Alamofire
class Vehicles: UITableViewController,
UISearchResultsUpdating, UISearchBarDelegate {
//variables
var model: NSMutableArray = []
var numberOfVehicles: NSMutableArray = []
var price: NSMutableArray = []
var imagePathString: NSMutableArray = []
var detailpage: NSMutableArray = []
var populator: NSMutableArray = []
var searching = false
var matches = [Int]()
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet weak var InfoTableView: UITableView!
var InfoList: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
loadData()
//this should reload but, it didn't.
self.InfoTableView.reloadData()
//then the searchbar that is good and don't have any problem.
searchingField()
}
func loadData() {
//read data from database
let rootRef = Database.database().reference()
let conditionalRef = rootRef.child("Vehicles")
conditionalRef.observe(.value) {(snap: DataSnapshot) in
// Get all the children from snapshot you got back from Firebase
let snapshotChildren = snap.children
// Loop over all children in Firebase
while let child = snapshotChildren.nextObject() as? DataSnapshot {
// Get code node key and save it to they array
self.populator.add(child.key)
if self.populator.contains("\(child.key)") {
let userRef = rootRef.child("Vehicles").child("\(child.key)")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let userDict = snapshot.value as! [String: Any]
let model1 = userDict["Model"] as! String
self.model.add(model1)
let detail1 = userDict["Detail"] as! String
self.detailpage.add(detail1)
let numberOfVehicles1 = userDict["numberOfVehicles"] as! String
self.numberOfVehicles.add(numberOfVehicles1)
let Price1 = userDict["Price"] as! String
self.price.add(Price1)
let imageURL1 = userDict["imageURL"] as! String
self.imagePathString.add(imageURL1)
}) //end second observeSingleEvent
}
else {
let alert = UIAlertController(title: "Error", message: "No one vehicle found", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "ok", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
} //end searching object in Vehicles node
} //end first observeSingleEvent
}//end func
func searchingField() {
//setup searchbar
tableView.estimatedRowHeight = 50
navigationController?.navigationBar.prefersLargeTitles = true
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.backgroundColor = UIColor.white
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search"
navigationItem.searchController = searchController
definesPresentationContext = true
let attributes = [
NSAttributedString.Key.foregroundColor : UIColor.black,
NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 17)
]
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes(attributes, for: .normal)
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Dismiss"
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self])
}
// MARK: Search Controller
func updateSearchResults(for searchController: UISearchController) {
var regArray = self.model as NSArray as! [String]
if let searchText = searchController.searchBar.text,
!searchText.isEmpty {
matches.removeAll()
for index in 0..<model.count {
if regArray[index].lowercased().contains(
searchText.lowercased()) {
matches.append(index)
}
}
searching = true
} else {
searching = false
}
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return searching ? matches.count : model.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searching ? matches.count : model.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "TableCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! Vehicles_cell
let row = indexPath.row
var regArray = self.model as NSArray as! [String]
cell.Label.text = searching ? regArray[matches[row]] : model[row] as! String
cell.Subtitle?.text = "N. Vehicles: \(self.numberOfVehicles[indexPath.row]) - Price: \(self.price[indexPath.row])$"
Alamofire.request("\(self.imagePathString[indexPath.row])").response { response in
guard let image = UIImage(data:response.data!) else {
// Handle error
return
}
let imageData = image.jpegData(compressionQuality: 1.0)
cell.Image.contentMode = .scaleAspectFit
cell.Image.image = UIImage(data : imageData!)
}
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowrentDetails" {
let myIndexPath = self.tableView.indexPathForSelectedRow!
//save detail1 in UserDefault
let SVDetail = self.detailpage[myIndexPath.row]
let SVDetaildefaults = UserDefaults.standard
SVDetaildefaults.set(SVDetail, forKey: "sv_detail")
SVDetaildefaults.synchronize()
_ = segue.destination
as! Vehicles_Detail
}
}
//IMPOSTA LE DIMENSIONI DELLE CELLE
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
default:
return 100
}
}
}
I expect the table show on the opening all the data from database, while actually and not repeat unless I click on the searchbar. And the table shouldn't be repeated twice.
Edit (solution to duplicates)
This is so embarrassing. The answer to this problem is simple
In numberOfSections function, I used address.count instead to use 1 Section. So, what I saw were not duplicate cells, but new block sections of model.count
Your tableview isn't reloading data once it is fetched during the Firebase observation, but is in updateSearchResults(). Does adding self.InfoTableView.reloadData() inside your loadData() in between the //end searching object in Vehicles node and //end first observeSingleEvent closing brackets fix the issue?
Edit: The reason your reload of tableview data doesn't fix the issue within viewDidLoad() is because it gets called before the loadData() function starts to iterate through your Firebase data objects. By doing it at the end of the Firebase observation, you're ensuring that you've loaded all of your data from Firebase prior to calling the reload.

Image not behaving accurately in data search results on TableView

I have data coming from Firebase and when the data is loaded I either want the an image to be hidden or shown based on some logic in my custom cell. It works perfectly fine when the data isn't being filtered but the second I type in the search bar or change the scope bar to a different index the image doesn't behave right.
For example: Index 0 should not have the image and index 1 should. Which is how it displays when it first loads. However, when I search I know the previous index 1 (now index 0) should still have it's image but it doesn't. BUT if I click to go to the detail controller it brings me to the right page. It's like it loads all the accurate info but does the logic on the original index 0. I would love some help as I have been searching for an answer FOREVER. Thank you in advance!
tableViewCell:
class SearchTalentCell: UITableViewCell {
#IBOutlet weak var userProfileImage: UIImageView!
#IBOutlet weak var talentUserName: UILabel!
#IBOutlet weak var selectedImg: UIImageView!
#IBOutlet weak var inviteSentImg: UIImageView!
var prospectRef: FIRDatabaseReference!
//#IBOutlet weak var radioButton: UIButton!
var currentTalent: UserType!
//var delegate: SearchCellDelegate?
func setTalent(talent: UserType) {
currentTalent = talent
currentTalent.userKey = talent.userKey
}
override func awakeFromNib() {
super.awakeFromNib()
let tap = UITapGestureRecognizer(target: self, action: #selector(selectTapped))
tap.numberOfTapsRequired = 1
selectedImg.addGestureRecognizer(tap)
selectedImg.isUserInteractionEnabled = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
/*#IBAction func radioButtonTapped(_ sender: Any) {
delegate?.didTapRadioButton(userKey: currntTalent.userKey, searchSelected: currntTalent.searchSelected!.rawValue, radioButton: radioButton)
}*/
func configureCell(user: UserType, img: UIImage? = nil) {
prospectRef = Cast.REF_PRE_PRODUCTION_CASTING_POSITION.child(ProjectDetailVC.currentProject).child(FIRDataCast.prospect.rawValue).child(CastingDetailVC.positionName).child(user.userKey)
//setTalent(talent: user)
self.talentUserName.text = "\(user.firstName) \(user.lastName)"
//self.inviteSentImg.image = UIImage(named: "inviteSent")
//user.adjustSearchSelected(talent: user, radioButton: radioButton)
prospectRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
print("**Image hidden")
} else {
self.inviteSentImg.image = UIImage(named: "inviteSent")
print("**Image shown")
}
})
//Image Caching
if img != nil {
self.userProfileImage.image = img
} else {
if let imageURL = user.profileImage {
let ref = FIRStorage.storage().reference(forURL: imageURL)
ref.data(withMaxSize: 2 * 1024 * 1024, completion: { (data, error) in
if error != nil {
print("ZACK: Unable to download image from Firebase Storage")
} else {
print("ZACK: Image downloaded from Firebase Storage")
if let imgData = data {
if let img = UIImage(data: imgData) {
self.userProfileImage.image = img
SearchTalentVC.userProfileImageCache.setObject(img, forKey: imageURL as NSString)
}
}
}
})
}
}
}
Viewcontroller:
class SearchTalentVC: UITableViewController/*, SearchCellDelegate*/ {
var searchingRole = [Cast]()
var unfilteredTalent = [UserType]()
var filteredTalent = [UserType]()
var selectedTalent = [UserType]()
var matchingTalentUserKeys = [String]()
var isFiltered = false
var prospectRef: FIRDatabaseReference!
static var userProfileImageCache: NSCache<NSString, UIImage> = NSCache()
let searchController = UISearchController(searchResultsController: nil)
//#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Talent"
searchController.searchBar.barStyle = .black
navigationItem.searchController = searchController
definesPresentationContext = true
searchController.searchBar.scopeButtonTitles = ["All", "Role Specific"]
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
getTalentProfiles()
}
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredTalent = unfilteredTalent.filter({ (talent : UserType) -> Bool in
let doesTalentMatch = (scope == "All") || doesUserKeyMatch(talent: talent.userKey)
if searchBarIsEmpty() {
return doesTalentMatch
} else {
let fullName = "\(talent.firstName) \(talent.lastName)"
return doesTalentMatch && fullName.lowercased().contains(searchText.lowercased())
}
})
tableView.reloadData()
}
func doesUserKeyMatch(talent: String) -> Bool {
self.filterRoleFeature()
return matchingTalentUserKeys.contains(talent)
}
func isSearching() -> Bool {
let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if isSearching() {
return filteredTalent.count
} else {
return unfilteredTalent.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "userSearchCell"
if let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? SearchTalentCell {
var talent: UserType
if isSearching() {
print("we are searching")
talent = self.filteredTalent[indexPath.row]
print("indexPath: \(indexPath.row)")
} else {
print("we are not searching")
talent = self.unfilteredTalent[indexPath.row]
}
if let imageURL = talent.profileImage {
if let img = SearchTalentVC.userProfileImageCache.object(forKey: imageURL as NSString) {
cell.configureCell(user: talent, img: img)
} else {
cell.configureCell(user: talent)
//cell.delegate = self
}
return cell
} else {
cell.configureCell(user: talent)
//cell.delegate = self
return SearchTalentCell()
}
} else {
return SearchTalentCell()
}
}
extension SearchTalentVC: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
self.tableView.reloadData()
}
}
extension SearchTalentVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
If you are hidding image in If part then you should put logic of showing image also in else block. See if this solve your problem.
if let _ = snapshot.value as? NSNull {
self.inviteSentImg.isHidden = true
print("**Image hidden")
} else {
self.inviteSentImg.isHidden = false
self.inviteSentImg.image = UIImage(named: "inviteSent")
print("**Image shown")
}

How to use search bar to fetch data from json result using swift?

Requirement : i need to filter the JSON data in UITableView with UISearchBar so i placed UISearchBar (not UISearchBarController) to top of my view controller and i placed UITableView below to the UISearchBarand I also have api key which contains data in json format .
code in my view controller:
class FourthViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UITabBarControllerDelegate,UISearchDisplayDelegate{
var arrDict = NSMutableArray()
var FilteredData = NSMutableArray()
var userid:String!
#IBOutlet var SearchButton: UISearchBar!
#IBOutlet var SlideShow: ImageSlideshow!
#IBOutlet var MyTableView: UITableView!
#IBOutlet var PostButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.hidden = true
SearchButton.delegate = self
jsonParsingFromURL()
SlideShow.backgroundColor = UIColor.whiteColor()
SlideShow.slideshowInterval = 5.0
SlideShow.pageControlPosition = PageControlPosition.UnderScrollView
SlideShow.pageControl.currentPageIndicatorTintColor = UIColor.lightGrayColor()
SlideShow.pageControl.pageIndicatorTintColor = UIColor.blackColor()
SlideShow.contentScaleMode = UIViewContentMode.ScaleAspectFill
SlideShow.setImageInputs(alamofireSource)
}
func jsonParsingFromURL () {
if Reachability.isConnectedToNetwork() == true
{
Alamofire.request(.GET, "http://something.com", parameters: nil, encoding: .URL, headers: nil).response { (req, res, data, error) -> Void in
let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
print(dataString)
self.startParsing(data!)
}
}
else{
let alert = UIAlertController(title: "No Internet Connection", message: "make sure your device is connected to the internet", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
func startParsing(data :NSData)
{
let dict: NSDictionary!=(try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
for i in 0 ..< (dict.valueForKey("ads") as! NSArray).count
{
arrDict.addObject((dict.valueForKey("ads") as! NSArray) .objectAtIndex(i))
}
MyTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrDict.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell") as! FirstTableViewCell
let strTitle : NSString=arrDict[indexPath.row] .valueForKey("categoryname") as! NSString
let photoImage : NSString=arrDict[indexPath.row] .valueForKey("image1") as! NSString
let SecondImage : NSString=arrDict[indexPath.row] .valueForKey("image2") as! NSString
let ThirdImage : NSString=arrDict[indexPath.row] .valueForKey("image3") as! NSString
let FourthImage : NSString=arrDict[indexPath.row] .valueForKey("image4") as! NSString
let URL_API_HOST2:String = "https://www.imagestring.com/"
// let FourthData = NSData(contentsOfURL: NSURL(string: URL_API_HOST2 + (FourthImage as String))!)
cell.image1.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (photoImage as String)))
cell.image2.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (SecondImage as String)))
// cell.image2.image = UIImage(data: SecData!)
cell.image3.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (ThirdImage as String)))
cell.image4.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (FourthImage as String)))
cell.CategoryName.text = strTitle as String
return cell
}
Issue : I have already loaded one api key which is known as category..now i need fetch subcategory data using search bar..subcategory has another api....
Apple statement : UISearchController object manages the display of search results based on interactions with a search bar. description here
If you'r using UISearchBar
import UIKit
class TDSearchVC: UIViewController ,UITableViewDataSource,UITableViewDelegate , UISearchResultsUpdating , UISearchBarDelegate{
//MARK:- Outlets
//MARK:-
#IBOutlet var tblSearch: UITableView!
//MARK:- Properties
//MARK:-
var dataArray = [String]()
var filteredArray = [String]()
var shouldShowSearchResults = false
var searchController: UISearchController!
//MARK:- VDL
//MARK:-
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
loadListOfCountries() // get the data from file
configureSearchController() // Config Controller in VC
}
//MARK:- VC Methods
//MARK:-
func loadListOfCountries() {
// Specify the path to the countries list file.
let pathToFile = Bundle.main.path(forResource: "Country", ofType: "txt")
if let path = pathToFile {
// Load the file contents as a string.
do{
let countriesString = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
self.dataArray = countriesString.components(separatedBy: "\n")
}
catch{
print("try-catch error is catched!!")
}
tblSearch.reloadData()
}
}
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
self.tblSearch.tableHeaderView = searchController.searchBar
}
//MARK:- table datasource
//MARK:-
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if shouldShowSearchResults {
return filteredArray.count
}
else {
return dataArray.count
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
if shouldShowSearchResults {
cell.textLabel?.text = filteredArray[indexPath.row]
}
else {
cell.textLabel?.text = dataArray[indexPath.row]
}
return cell
}
//MARK:- search update delegate
//MARK:-
public func updateSearchResults(for searchController: UISearchController){
let searchString = searchController.searchBar.text
// Filter the data array and get only those countries that match the search text.
filteredArray = dataArray.filter({ (country) -> Bool in
let countryText: NSString = country as NSString
return (countryText.range(of: searchString!, options: .caseInsensitive).location) != NSNotFound
})
tblSearch.reloadData()
}
//MARK:- search bar delegate
//MARK:-
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
shouldShowSearchResults = true
tblSearch.reloadData()
}
public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
shouldShowSearchResults = false
tblSearch.reloadData()
}
}
If you'r using UITextField
import UIKit
class TDSearchVC: UIViewController , UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate{
#IBOutlet var textSearch: UITextField!
#IBOutlet var tblSearchResult: UITableView!
var arrData : [String] = []
var arrFilterData : [String] = []
var isSearch : Bool!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
isSearch = false
/*
* If date Data is in Json then use JSON Serialization
*/
arrData = ["Apple", "Banana", "Chikoo", "Brew", "Cherry", "Mango", "Lotus", "Peacock", "Temple", "Pine Apple","Glass", "Rose", "Church", "Computer", "Carrot"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK:- textfield
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
var searchText = textField.text! + string
if string == "" {
searchText = (searchText as String).substring(to: searchText.index(before: searchText.endIndex))
}
if searchText == "" {
isSearch = false
tblSearchResult.reloadData()
}
else{
getSearchArrayContains(searchText)
}
return true
}
// Predicate to filter data
func getSearchArrayContains(_ text : String) {
var predicate : NSPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", text)
arrFilterData = (arrData as NSArray).filtered(using: predicate) as! [String]
isSearch = true
tblSearchResult.reloadData()
}
// MARK:- TableView Delegates
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if isSearch! {
return arrFilterData.count
}
else{
return arrData.count
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
var cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
if isSearch! {
cell.textLabel?.text = arrFilterData[indexPath.row]
}
else{
cell.textLabel?.text = arrData[indexPath.row]
}
return cell
}
}

Resources