I'm Trying to have tableview with a search controller pass image Array from Json file to a new viewcontroller based on what option the user picks in search bar tableview. I have created a search bar for my App that displays will display all of the information in the app so the user can easily pick the pictures they want to see. That works normally by using a tableview, and when the user pick a row, it sends a variable with the associated pictures to an image view on the other screen.
Because of the amount of options I have, I created a Json file. I have it coded where it will return options based on what the user types into the search bar. My problem is that I am unable to pass the Image Array from the .json file to the image view controller. It will display the viewcontroller, but the "array" imageview is blank as no picture array is being passed. Below is my code and am wondering if anyone has any ideas that could point me in the right direction, or tell me what I am doing wrong.
Search Bar code:
import UIKit
class ProtocolCell: UITableViewCell {
#IBOutlet weak var pNameLabel: UILabel!
}
extension String {
func trimmed() -> String {
return self.trimmingCharacters(in: .whitespaces)
}
}
class SearchController: UIViewController, UISearchBarDelegate {
/// Search Bar
#IBOutlet weak var pSearchBar: UISearchBar!
/// Proto Array
fileprivate var myProtocols:[Protocols]?
/// Searhed Array
fileprivate var searchedProtocols:[Protocols]?
/// TableView
#IBOutlet weak var protocolsTV: UITableView!
/// Is Searching
fileprivate var isSearching:Bool=false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
protocolsTV.tableFooterView=UIView()
pSearchBar.delegate=self
myProtocols=[Protocols]()
searchedProtocols=[Protocols]()
myProtocols?.removeAll()
searchedProtocols?.removeAll()
myProtocols=Functions.getAllProtocolsFromJson()
if protocolsTV.delegate == nil {
protocolsTV.delegate=self
protocolsTV.dataSource=self
}
protocolsTV.reloadData()
}
}
extension SearchController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return isSearching == false ? (myProtocols?.count ?? 0) : (searchedProtocols?.count ?? 0)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProtocolCell") as! ProtocolCell
cell.pNameLabel.text=isSearching == false ? (myProtocols![indexPath.row].pName ?? "") : (searchedProtocols![indexPath.row].pName ?? "")
return cell
}
//EDIT TABLE FUNCTION HERE!!!!!//
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Is Searching: \(isSearching) ImagesArray: \(isSearching==true ? (searchedProtocols?[indexPath.row].imagesName ?? []) : (myProtocols?[indexPath.row].imagesName ?? []))")
let Vc = self.storyboard?.instantiateViewController(withIdentifier: "imageViewController") as! imageViewController
let home = self.storyboard?.instantiateViewController(withIdentifier: "FIRST") as! ViewController
//switch indexPath.section
// {
// case 0:
if searchedProtocols?[indexPath.row].pName == "test" {
let arrayStorage = myProtocols?[indexPath.row].imagesName ?? []
Vc.passedArray = arrayStorage
print(arrayStorage)
print(myProtocols?[indexPath.row].imagesName ?? [])
self.navigationController?.pushViewController(Vc, animated: true)
}
else {
self.navigationController?.pushViewController(home, animated: true)
}
// break;
// default:
// self.navigationController?.pushViewController(home, animated: true)
// }
}
func updateSearchData(With searchText: String, In searchBar: UISearchBar) {
if searchText.trimmed().count == 0 {
isSearching=false
searchBar.setShowsCancelButton(false, animated: true)
} else {
isSearching=true
searchBar.setShowsCancelButton(true, animated: true)
}
if isSearching {
/// We Are Searching Sort Array
if searchedProtocols == nil { searchedProtocols=[Protocols]() }
searchedProtocols?.removeAll()
searchedProtocols=myProtocols!.filter({($0.pName ?? "").lowercased().contains(searchText.lowercased())})
/// Make Set So, Data isn't Repeated
searchedProtocols=Array(Set(searchedProtocols ?? []))
} else {
/// Searching is Stopped
searchedProtocols?.removeAll()
}
protocolsTV.reloadData()
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
updateSearchData(With: searchText, In: searchBar)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.view.endEditing(true)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
searchBar.text=nil
isSearching=false
searchedProtocols?.removeAll()
protocolsTV.reloadData()
self.view.endEditing(true)
}
}
Other Used Code:
class Protocols: NSObject {
var pName:String?
var imagesName:[UIImage]!
override init() {}
init(With Dict: [String:Any]) {
pName=Dict["name"] as? String ?? ""
imagesName=Dict["imagesArray"] as? [UIImage] ?? []
}
ImageViewController:
class imageViewController: UIViewController,GADBannerViewDelegate, UIGestureRecognizerDelegate, UIScrollViewDelegate {
#IBOutlet weak var pageControl: UIPageControl!
var bannerView: GADBannerView!
var index = 0
var mySelectedProtocol:Protocols?
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var myImageView: UIImageView!
#IBAction func pictureSwipe(_ sender: Any) {
let pictureString = self.passedArray[index]
self.myImageView.image = pictureString
index = (index < passedArray.count-1) ? index+1 : 0
self.pageControl.numberOfPages = passedArray.count
self.pageControl.currentPage = index
}
#IBAction func pictureswipeback(_ sender: Any) {
let pictureString = self.passedArray[index]
self.myImageView.image = pictureString
index = (passedArray.count-1)
self.pageControl.numberOfPages = passedArray.count
self.pageControl.currentPage = index
}
func configurePageControl() {
self.pageControl.numberOfPages = passedArray.count
self.pageControl.currentPage = 0
self.pageControl.pageIndicatorTintColor = UIColor.white
self.pageControl.currentPageIndicatorTintColor = UIColor.red
self.view.addSubview(pageControl)
if index == 1 {
self.pageControl.currentPage = 1
}
func updateCurrentPageDisplay(){
self.pageControl.numberOfPages = passedArray.count
}
}
var passedImage : UIImage! = nil
var passedArray : [UIImage]!
override func viewDidLoad(){
super.viewDidLoad()
self.myImageView.image = passedArray.first
configurePageControl()
scrollView.delegate = self
self.navigationController?.navigationBar.isHidden = false
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 5.0
In Destination Controller
class DestinationVC: UIViewController {
var mySelectedProtocol:Protocols?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if mySelectedProtocol == nil { self.navigationController?.popViewController(animated: true) }
/// We have Data
print("Img Array with Name ==> \(mySelectedProtocol?.imagesName ?? [])")
}
}
In Source Controller TableView Delegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Is Searching: \(isSearching) ImagesArray: \(isSearching==true ? (searchedProtocols?[indexPath.row].imagesName ?? []) : (myProtocols?[indexPath.row].imagesName ?? []))")
let vc:DestinationVC=mainStoryBoard.instantiateViewController(withIdentifier: "DestinationVC") as! DestinationVC
vc.mySelectedProtocol=isSearching==true ? (searchedProtocols?[indexPath.row]) : (myProtocols?[indexPath.row])
self.navigationController?.pushViewController(vc, animated: true)
}
Update 2 - Show Images as PageViewController
private func addPageView() {
myScrollView.backgroundColor=UIColor.clear
myScrollView.isUserInteractionEnabled=true
myScrollView.showsHorizontalScrollIndicator=false
myScrollView.isPagingEnabled=true
myScrollView.delegate=self
myScrollView.bounces=false
self.count=mySelectedProtocol!.imagesName!.count
for i in 0..<self.count {
///Get Origin
let xOrigin : CGFloat = CGFloat(i) * myScrollView.frame.size.width
///Create a imageView
let imageView = UIImageView()
imageView.frame = CGRect(x: xOrigin, y: 0, width: myScrollView.frame.size.width, height: myScrollView.frame.size.height)
imageView.contentMode = .scaleAspectFit
imageView.image=UIImage(named: mySelectedProtocol!.imagesName![i])
myScrollView.addSubview(imageView)
}
setUpPageControl()
///Set Content Size to Show
myScrollView.contentSize = CGSize(width: myScrollView.frame.size.width * CGFloat(self.count), height: myScrollView.frame.size.height)
}
Related
I did a parse json in my listingshopvc and it shows.Now I want to select a row and it pops up another view controller but there's error just a blank page with no error. I just want to press a row and convert it to show up on another view controller.
I have listing in the following view controller: ListingShopVc,ProductDetail,TableCellData
ListingShopVC
import UIKit
import CoreData
class ListingShopVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var creditsdisplay: UILabel!
var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var myUser:[User] = []
var mySecond:[Product] = []
var id:String = ""
var name:String = ""
var price:Double = 0.0
var image:String = ""
var details:String = ""
override func viewDidLoad() {
super.viewDidLoad()
fetch()
tableView.delegate = self
tableView.dataSource = self
extracted()
creditsdisplay.text = "You have 200 credits"
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return mySecond.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "hello", for: indexPath) as! TableCellData
// Configure the cell...
cell.shopTitle.text = mySecond[indexPath.row].name
cell.shopPrice.text = "$" + String(mySecond[indexPath.row].price) + "0"
cell.shopDesc.text = mySecond[indexPath.row].description
if let url = URL(string: mySecond[indexPath.row].image){
DispatchQueue.global().async {
let data = try? Data(contentsOf: url)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.shopImageView.image = image
}
}
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
id = mySecond[indexPath.row].id
name = mySecond[indexPath.row].name
price = mySecond[indexPath.row].price
details = mySecond[indexPath.row].description
image = mySecond[indexPath.row].image
performSegue(withIdentifier: "toDetails", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetails"{
let vc = segue.destination as! ProductDetail
vc.productPicture = image
vc.productName = name
vc.productPrice = price
vc.productDetails = details
vc.productID = id
print(vc.productName)
}
}
func extracted(){
guard let url = URL(string: "http://rajeshrmohan.com/sport.json")
else {return}
let task = URLSession.shared.dataTask(with: url){
(data,response,error) in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return
}
do {
let decoder = JSONDecoder()
let model:[Product] = try decoder.decode([Product].self, from: dataResponse)
//print(model)
for i in 0..<model.count{
self.mySecond.append(model[i])
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
}
func fetch(){
userList = try! context.fetch(User.fetchRequest())
tableView.reloadData()
}
}
TableViewCell
import UIKit
class TableCellData: UITableViewCell {
#IBOutlet weak var shopImageView: UIImageView!
#IBOutlet weak var shopTitle: UILabel!
#IBOutlet weak var shopPrice: UILabel!
#IBOutlet weak var shopDesc: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
ProductDetail
import UIKit
import CoreData
class ProductDetail: UIViewController {
var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var myArray:[Cart] = []
var mySecondArray:[Products] = []
var newTots:Double = 0.0
#IBOutlet weak var AddImage: UIImageView!
#IBOutlet weak var AddTitle: UILabel!
#IBOutlet weak var AddPrice: UILabel!
#IBOutlet weak var AddDesc: UILabel!
var productID = String()
var productName = String()
var productPrice:Double = 0.0
var productPicture = String()
var productDetails:String = ""
override func viewDidLoad() {
super.viewDidLoad()
AddTitle.text = productName
AddDesc.text = productDetails
AddPrice.text = String(productPrice)
if let imageUrl = URL(string: productPicture),
let imageData = try? Data(contentsOf: imageUrl) {
AddImage.image = UIImage(data: imageData)
}
}
#IBAction func add2Cart(_ sender: Any) {
let neww = Cart(context: context)
neww.image = productPicture
neww.name = productName
neww.desc = productDetails
neww.price = productPrice
neww.total = productPrice
try! context.save()
performSegue(withIdentifier: "gotoCheckout", sender: nil)
}
func fetch(){
self.mySecondArray = try! context.fetch(Products.fetchRequest())
}
}
What it shows it this [1]: https://i.stack.imgur.com/XWUt0.png
-> You just need to call a delegate method of table view didSelectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let tag = projectEquipmentList?[indexPath.row].tag // Object data to take in next VC
let QR = R.storyboard.main.qrScannerVC()! // View Controller
QR.manageVC(projectEquipmentTag: tag!) // setter method of View controller to set data
navigationController?.pushViewController(QR, animated: true) // push to next view controller
}
initially I am able to show all rows in tableview.. now i need to show only searched textfield rows...
here the textfield and search button is outside the tableview.. now if i add date in textfield and tap on search button then i need to show only the date contain row only in tableview how to do that
code to show all rows in tableview: here in postedServicesCall param's from_date is nil then i need to show all rows .. which i am able to do with below code.. now how to show if there is a value in from_date then only the date contained rows in tableview
class PageContentViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var fromDateTextField: MDCTextField!
private var servicesArray = [ServicesModel]()
override func viewDidLoad() {
postedServicesCall()
DispatchQueue.main.async {
self.servicesTableView.reloadData()
}
}
func postedServicesCall(){
let param = ["from_date" : ""]
APIReqeustManager.sharedInstance.serviceCall(param: param as [String : Any], method: .post, loaderNeed: false, loadingButton: nil, needViewHideShowAfterLoading: nil, vc: self, url: CommonUrl.posted_requests, isTokenNeeded: true, isErrorAlertNeeded: true, isSuccessAlertNeeded: false, actionErrorOrSuccess: nil, fromLoginPageCallBack: nil) { [weak self] (resp) in
self?.postedServicesData = Posted_services_base_model(dictionary: resp.dict as NSDictionary? ?? NSDictionary())
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return servicesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ServicesTableViewCell", for: indexPath) as! ServicesTableViewCell
cell.serviceTitle.text = servicesArray[indexPath.row].title
cell.dateLabel.text = servicesArray[indexPath.row].date
cell.locationLabel.text = servicesArray[indexPath.row].location
return cell
}
//if i add date in textfield and tap on search.. then with the date how many rows are there should be display in tableview
#IBAction func searchtBtn(_ sender: TransitionButton) {
}
if i search date in textfield then i need to show the date related rows in tableview.. how?
please do help with code
try this easy search implementation
//
// ViewController.swift
//
// Created by Rajesh Gandru on 4/12/21.
//
import UIKit
//MARK:- User Model Class
struct User {
var userName: String?
var userNumber : String?
var UserAge : String?
}
//MARK:- tableview cell
class ExampleCell:UITableViewCell{
#IBOutlet weak var resultLBLref:UILabel!
}
class ViewController: UIViewController {
//MARK:- Class Outlets...
#IBOutlet weak var searchtextfeildref: UITextField!
#IBOutlet weak var tableViewref: UITableView!
//MARK:- Class Properties...
var listArr : [User] = []
var filteredlistArr :[User] = []
var searchMyOrders = false
//MARK:- View Lyfe cycle starts here..
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.listArr = [User(userName: "Raj", userNumber: "78623", UserAge: "34"),User(userName: "Ram", userNumber: "67467645", UserAge: "22"),User(userName: "Raki", userNumber: "5634534", UserAge: "43"),User(userName: "Raksha", userNumber: "098098", UserAge: "18"),User(userName: "Ravi", userNumber: "7863846", UserAge: "24")]
self.searchtextfeildref.addTarget(self, action: #selector(self.textFieldDidChange(_:)),
for: UIControl.Event.editingChanged)
}
//MARK:- Textfeild Search
#objc func textFieldDidChange(_ textField: UITextField) {
// filter tableViewData with textField.text
let searchText = textField.text
//by_bus_cities_drop_address
filteredlistArr = self.listArr.filter {
return (($0.userName?.localizedLowercase.contains(searchText!))! ||
$0.userNumber!.localizedLowercase.contains(searchText!))
} ?? []
if(filteredlistArr.count == 0){
searchMyOrders = false;
} else {
searchMyOrders = true;
}
self.tableViewref.reloadData()
}
}
//MARK:- Tableview Content
extension ViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchMyOrders {
return filteredlistArr.count
}else {
return listArr.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ExampleCell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as! ExampleCell
if searchMyOrders {
cell.resultLBLref.text = filteredlistArr[indexPath.row].userName
}else {
cell.resultLBLref.text = listArr[indexPath.row].userName
}
return cell
}
}
I am in a bind.
My regular developer has secured a full time gig, and I am trying to finish a project.
Literally stuck on the last line of code.....
I have a tableview that parses a json file to populate and open a pdf file when a row is selected.
I reworked the tableview in order to add a searchbar and associated code, which works when running the bundle.
I am, however, stuck with connecting the didSelectRow with the appropriate pdf file.
Can someone please lend a hand? Thanks
import UIKit
import WebKit
// Model
struct Section {
var section: String
var pdfs: [PDF]
}
struct PDF {
var code: String
var name: String
var airport: String
}
class PdfVC: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var webView: WKWebView!
#IBOutlet weak var tableViewLeft: NSLayoutConstraint!
#IBOutlet weak var btnMenuLeft: NSLayoutConstraint!
#IBOutlet weak var btnMenu: UIButton!
#IBOutlet weak var searchBar: UISearchBar!
//json
var jsonData: [Section] = []
var filtedJsonData: [Section] = []
//WebView
var fileName: String?
var isVideo: Bool = false
var btnMenuClose:UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
hideKeyboardWhenTappedAround()
// Setup TableView
tableView.delegate = self
tableView.dataSource = self
setupData()
tableView.reloadData()
// Setup SearchBar
searchBar.delegate = self
// Setup WebView
if let fileName = fileName {
isVideo = fileName.contains(".mp4")
if let range = fileName.range(of: isVideo ? ".mp4" : ".pdf") {
self.fileName!.removeSubrange(range)
}
}
if let file = Bundle.main.url(forResource: fileName ?? "", withExtension: isVideo ? ".mp4" : ".pdf", subdirectory: nil, localization: nil) {
let request = URLRequest(url: file)
webView.load(request)
}
if let image = UIImage(named: "ico_close") {
navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(onWebTap))
//self.navigationItem.leftItemsSupplementBackButton = true
btnMenuClose = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(onWebTap))
self.navigationItem.rightBarButtonItems = [btnMenuClose!];
}
//navigationItem.title = "Airport Maps"
}
private func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc private func dismissKeyboard() {
view.endEditing(true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
// title color to white
let titleTextAttributed: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white, .font: UIFont(name: "HelveticaNeue-Light", size: 20) as Any]
self.navigationController?.navigationBar.titleTextAttributes = titleTextAttributed
// back arrow white
self.navigationController?.navigationBar.tintColor = UIColor.white
// blueish navigation bar
self.navigationController?.navigationBar.barTintColor = UIColor(red: 0.00, green: 0.54, blue: 0.92, alpha: 1.00)
self.navigationController?.navigationBar.isTranslucent = false
showMenu(false, animated: false)
}
private func setupData() {
// Parse data from local json file
if let path = Bundle.main.path(forResource: "airports", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? [Dictionary<String, String>] {
for result in jsonResult {
if !jsonData.contains(where: { $0.section == result["Section"] }) {
let section = Section(section: result["Section"] ?? "", pdfs: [])
jsonData.append(section)
}
let pdf = PDF(code: result["Code"] ?? "", name: result["Filename"] ?? "", airport: result["Name"] ?? "")
let index = jsonData.firstIndex(where: { $0.section == result["Section"] })
if let index = index {
jsonData[index].pdfs.append(pdf)
}
}
}
} catch {
// Handle error
print("error parsing json")
}
}
// Sort data before use
jsonData.sort(by: { $0.section < $1.section })
for index in 0..<jsonData.count {
jsonData[index].pdfs.sort(by: { $0.airport < $1.airport } )
}
filtedJsonData = jsonData
}
#objc func onWebTap() {
var left:CGFloat = 0
if tableViewLeft.constant == 0 {
left = -320
}
tableViewLeft.constant = left
showMenu(left != 0, animated: true)
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
func showMenu(_ show:Bool, animated:Bool) {
if let image = UIImage(named: show ? "ico_open" : "ico_close") {
btnMenuClose?.image = image
//navigationItem.rightBarButtonItem?.image = image
//}
//var left:CGFloat = 20
//if show == false {
// left = -64
}
//btnMenuLeft.constant = left
UIView.animate(withDuration: animated ? 0.3 : 0.0, delay: 0, options: .curveEaseInOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
// TableView
extension PdfVC: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return filtedJsonData.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if filtedJsonData[section].pdfs.count == 0 {
return nil
}
return filtedJsonData[section].section
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filtedJsonData[section].pdfs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PdfCell", for: indexPath) as! PdfCell
let pdf = filtedJsonData[indexPath.section].pdfs[indexPath.row]
cell.setupCell(pdf: pdf)
return cell
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
dismissKeyboard()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let pdf = filtedJsonData[indexPath.section].pdfs[indexPath.row]
//THIS IS WHERE I'M STUCK<<<<<<<<<
self.title = pdf.airport
}
}
// SearchBar
extension PdfVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
for (index, data) in jsonData.enumerated() {
// Filter pdfs by code and name
let filtedPdf = data.pdfs.filter { $0.code.lowercased().prefix(searchText.count) == searchText.lowercased() || $0.airport.lowercased().prefix(searchText.count) == searchText.lowercased() }
filtedJsonData[index].pdfs = filtedPdf
}
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
tableView.reloadData()
}
}
Got it figured out. Thanks for all who spent some time reading my issue. I changed as follows
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let pdf = filtedJsonData[indexPath.section].pdfs[indexPath.row]
self.fileName = pdf.name
self.title = pdf.airport
DispatchQueue.main.async {
self.reloadWebView()
}
}
and added
private func reloadWebView() {
// Setup WebView
if let fileName = fileName {
isVideo = fileName.contains(".mp4")
if let range = fileName.range(of: isVideo ? ".mp4" : ".pdf") {
self.fileName!.removeSubrange(range)
}
}
if let file = Bundle.main.url(forResource: fileName ?? "", withExtension: isVideo ? ".mp4" : ".pdf", subdirectory: nil, localization: nil) {
let request = URLRequest(url: file)
webView.load(request)
}
}
I would like some help with the search bar functionality. I am stuck and not sure where to take it from here. I am trying to update the tableview when search text word is contained in a recipe title. I am not sure how to do this because of the depreciated searchDisplay controller. Help would be appreciated.
import UIKit
import SwiftyJSON
class Downloader {
class func downloadImageWithURL(_ url:String) -> UIImage! {
let data = try? Data(contentsOf: URL(string: url)!)
return UIImage(data: data!)
}
}
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UISearchDisplayDelegate{
#IBOutlet weak var recipeTable: UITableView!
// search functionality Need help with my search functionality
var filteredRecipes = [Recipe]()
func filterContentForSearch(searchText:String) {
// need help here
self.filteredRecipes = self.recipes.filter({(title:Recipe) -> Bool in
return (title.title!.lowercased().range(of: searchText.lowercased()) != nil)
})
}
private func searchDisplayController(controller: UISearchController!, shouldReloadTableForSearchString searchString: String!) -> Bool {
self.filterContentForSearch(searchText: searchString)
return true
}
//end search parameters
// tableview functionionalitys
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == searchDisplayController!.searchResultsTableView {
return filteredRecipes.count
}else{
return recipes.count
}
// recipeTable.reloadData()
}
// tableview functionalities
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RecipeTableViewCell
if tableView == self.searchDisplayController!.searchResultsTableView{
//get images from download
DispatchQueue.main.async { () ->Void in
cell.imageLabel.image = Downloader.downloadImageWithURL(self.filteredRecipes[indexPath.row].imageUrl)
}
cell.recipeLabel.text = self.filteredRecipes[indexPath.row].title
recipeTable.reloadData()
}else{
//get image from download
DispatchQueue.main.async { () ->Void in
cell.imageLabel.image = Downloader.downloadImageWithURL(self.recipes[indexPath.row].imageUrl)
}
cell.recipeLabel.text = recipes[indexPath.row].title
}
//recipeTable.reloadData()
return cell
}
// structs for json
struct Root : Decodable {
let count : Int
let recipes : [Recipe]
}
struct Recipe : Decodable { // It's highly recommended to declare Recipe in singular form
let recipeId : String
let imageUrl, sourceUrl, f2fUrl : String
let title : String?
let publisher : String
let socialRank : Double
let page : Int?
let ingredients : [String]?
}
//recipes is array of Recipes
var recipes = [Recipe]() // array of recipes
//unfiltered recipes to put into search
fileprivate func getRecipes() {
let jsonURL = "https://www.food2fork.com/api/search?key=264045e3ff7b84ee346eb20e1642d9d9"
//.data(using: .utf8)!
guard let url = URL(string: jsonURL) else{return}
URLSession.shared.dataTask(with: url) {(data, response , err) in
if let response = response as? HTTPURLResponse, response.statusCode != 200 {
print(response.statusCode)
return
}
DispatchQueue.main.async {
if let err = err{
print("failed to get data from URL",err)
return
}
guard let data = data else{return}
//print(String(data: data, encoding: .utf8))
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(Root.self, from: data)
self.recipes = result.recipes
//print(result.recipes)
self.recipeTable.reloadData()
}catch let jsonERR {
print("Failed to decode",jsonERR)
}
}
}.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
//recipeTable.reloadData()
//search bar
//filteredRecipes = recipes
//call json object
getRecipes()
}
}
You could take this approach:
Add a Boolean variable to indicate whether searching or not
var searching: Bool = false
Use this for numberOfRowsInSection for the tableview
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return filteredRecipes.count
} else {
return recipes.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RecipeTableViewCell
var recipe: Recipe
if searching {
recipe = filteredRecipes[indexPath.row]
} else {
recipe = recipes[indexPath.row]
}
DispatchQueue.main.async { () ->Void in
cell.imageLabel.image = Downloader.downloadImageWithURL(recipe.imageUrl)
}
cell.recipeLabel.text = recipe.title
return cell
}
And add this for the searchBar (set searching for other funcs like searchBarCancelButtonClicked)
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
searching = false
filteredRecipes.removeAll()
view.endEditing(true)
} else {
searching = true
filteredRecipes = recipes.filter{$0.title.contains(searchBar.text!)}
}
tableView.reloadData()
}
In my mainTableView Controller, I can print the API result in the console but I have no idea how I can set these to be visible in the cells of my tableview
import UIKit
//from: https://github.com/Ramotion/folding-cell
class MainTableViewController: UITableViewController {
let kCloseCellHeight: CGFloat = 179
let kOpenCellHeight: CGFloat = 488
let kRowsCount = 100
var cellHeights = [CGFloat]()
var restApi = RestApiManager()
var items: NSDictionary = [:]
override func viewDidLoad() {
super.viewDidLoad()
restApi.makeCall() { responseObject, error in
// use responseObject and error here
// self.json = JSON(responseObject!)
print("print the json data from api ")
self.items = NSDictionary(dictionary: responseObject!)
self.tableView.reloadData()
print(responseObject!.count)
// print(self.items)
let resultList = self.items["result"] as! [[String:
AnyObject]]
print(resultList[5])
}
createCellHeightsArray()
self.tableView.backgroundColor = UIColor(patternImage:
UIImage(named: "background")!)
}
// MARK: configure
func createCellHeightsArray() {
for _ in 0...kRowsCount {
cellHeights.append(kCloseCellHeight)
}
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard case let cell as DemoCell = cell else {
return
}
cell.backgroundColor = UIColor.clearColor()
if cellHeights[indexPath.row] == kCloseCellHeight {
cell.selectedAnimation(false, animated: false, completion:nil)
} else {
cell.selectedAnimation(true, animated: false, completion: nil)
}
cell.number = indexPath.row
}
// with as! the cell is set to the custom cell class: DemoCell
// afterwards all data can be loaded in this method
override func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("FoldingCell",
forIndexPath: indexPath) as! DemoCell
//TODO: set all custom cell properties here (retrieve JSON and set in
cell), use indexPath.row as arraypointer
// let resultList = self.items["result"] as! [[String: AnyObject]]
// let itemForThisRow = resultList[indexPath.row]
// cell.schoolIntroText.text = itemForThisRow["name"] as! String
cell.schoolIntroText.text = "We from xx University..."
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return cellHeights[indexPath.row]
}
// MARK: Table vie delegate
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as!
FoldingCell
if cell.isAnimating() {
return
}
var duration = 0.0
if cellHeights[indexPath.row] == kCloseCellHeight { // open cell
cellHeights[indexPath.row] = kOpenCellHeight
cell.selectedAnimation(true, animated: true, completion: nil)
duration = 0.5
} else {// close cell
cellHeights[indexPath.row] = kCloseCellHeight
cell.selectedAnimation(false, animated: true, completion:
nil)
duration = 0.8
}
UIView.animateWithDuration(duration, delay: 0, options:
.CurveEaseOut, animations: { () -> Void in
tableView.beginUpdates()
tableView.endUpdates()
}, completion: nil)
}
}
I get this result in JSON which is correct
{
result = (
{
city = Perth;
"cou_id" = AU;
environment = R;
image = "-";
name = "Phoenix English";
rating = 0;
"sco_id" = 2;
"sco_type" = LS;
},
{
city = "Perth ";
"cou_id" = AU;
environment = L;
image = "-";
name = "Milner college";
rating = 0;
"sco_id" = 3;
"sco_type" = LS;
},
what do I have to do to set these values and set them here?
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FoldingCell", forIndexPath: indexPath) as! DemoCell
//TODO: set all custom cell properties here (retrieve JSON and set in cell), use indexPath.row as arraypointer
cell.schoolIntroText.text = "We from xx University..."
return cell
}
I somehow dont figure out how to construct an array from this JSON output and how to access these fields which seem to be nested in many dimensions,
as a noob, thx for any inputs.
Addition from class restApi:
// working method for calling api
func makeCall(completionHandler: (NSDictionary?, NSError?) -> ()) {
Alamofire.request(
.GET,
baseURL+schools+nonAcademicParameter,
headers: accessToken
)
.responseJSON { response in
switch response.result {
case .Success(let value):
completionHandler(value as? NSDictionary, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}
}
At your TODO point:
let resultList = self.items["result"] as! [[String: AnyObject]]
let itemForThisRow = resultList[indexPath.row]
cell.cityLabel.text = itemForThisRow["city"] as! String
cell.nameLabel.text = itemForThisRow["name"] as! String
...
To make dealing with json easier in swift try SwiftyJSON.
I figured it out now. The size of the inner resultList array needs to be passed in numberOfRowsSelection. Then it loads the cell dynamically.
override func tableView(tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
print("size of self.resultlist.count: ")
print(self.resultList.count)
//size of the inner array with all the acutal values have to be 0
at the beginning. when the async call comes back with the whole
result, it will be updated. so it has to be set to the size of the
array
//http://www.unknownerror.org/opensource/Alamofire/Alamofire/q/stackoverflow/29728221/uitableview-got-rendered-before-data-from-api-returned-using-swiftyjson-and-alam
return self.resultList.count
}