Using AlamoFire to fetch data to populate UITableView based on UISearchBar value - json

Unlike many JSON requests, instead of filtering a long pre-determined JSON, I intend to send a JSON request (using AlamoFire) based on what is typed into a Search Bar, thus fetching the JSON to be parsed (with SwiftyJSON) to fill the UITableView
What I'd like to do is to use the searchTerm (typed into the searchbar) to send an AlamoFire request to Geonames using the searchTerm in the query field of geonames API request. i.e.
http://api.geonames.org/searchJSON?formatted=true&q=(searchTerm)&maxRows=3&username=demo
What I essentially cannot do is send the request AFTER filling out the Search Bar, and therefore populate the table with that data.
Below is my current code (which populates the table upon the view loading with parsed JSON data with a request for "burpham"
import UIKit
import Alamofire
import SwiftyJSON
class SearchAddLocationViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
{
#IBOutlet weak var tblJSON: UITableView!
#IBOutlet weak var searchbarValue: UISearchBar!
weak open var delegate: UISearchBarDelegate?
var arrRes = [[String:AnyObject]]() //Array of dictionary
override func viewDidLoad()
{
super.viewDidLoad()
}
public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) // called when text ends editing
{
callAlamo(searchTerm: searchbarValue.text!)
}
func callAlamo(searchTerm: String)
{
Alamofire.request("http://api.geonames.org/searchJSON?q=\(searchTerm)&maxRows=5&username=garethallenstringer").responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["geonames"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
}
if self.arrRes.count > 0 {
self.tblJSON.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "addLocProtoCell")!
var dict = arrRes[indexPath.row]
cell.textLabel?.text = dict["name"] as? String
cell.detailTextLabel?.text = dict["countryName"] as? String
return cell
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return arrRes.count
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

You need to listen func searchBarTextDidEndEditing(_ searchBar: UISearchBar) method of UISearchBar delegate for populating your UITableView
class ViewController: UIViewController, UISearchBarDelegate {
#IBOutlet private weak var searchBar: UISearchBar?
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar?.delegate = self
}
//MARK: UISearchBarDelegate methods
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
//You can do your request via Alamofire to populate tableView
}
}
UPDATE #1
import UIKit
import Alamofire
import SwiftyJSON
class SearchAddLocationViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate
{
#IBOutlet weak var tblJSON: UITableView!
#IBOutlet weak var searchbarValue: UISearchBar!
var arrRes = [[String:AnyObject]]() //Array of dictionary
override func viewDidLoad()
{
super.viewDidLoad()
self.searchbarValue.delegate = self
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { // called when text ends editing
{
callAlamo(searchTerm: searchbarValue.text!)
}
func callAlamo(searchTerm: String)
{
Alamofire.request("http://api.geonames.org/searchJSON?q=\(searchTerm)&maxRows=5&username=garethallenstringer").responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["geonames"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
}
if self.arrRes.count > 0 {
self.tblJSON.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "addLocProtoCell")!
var dict = arrRes[indexPath.row]
cell.textLabel?.text = dict["name"] as? String
cell.detailTextLabel?.text = dict["countryName"] as? String
return cell
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return arrRes.count
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Related

swift When I click on didselectRow I want to see the json data on the detail page image , title and year?

When I click on it, I want to show the picture title and year part in the cell section in the tableview, how can I do this? When we click on the row go detail page and big picture, title and year I want to show the big title and year. How can I populate the DetailViewController page?
ViewController
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
#IBOutlet var field: UITextField!
var movies = [Movie]()
override func viewDidLoad() {
super.viewDidLoad()
table.register(MovieTableViewCell.nib(), forCellReuseIdentifier: MovieTableViewCell.identifier)
table.delegate = self
table.dataSource = self
field.delegate = self
}
// Field
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
searchMovies()
return true
}
func searchMovies() {
field.resignFirstResponder()
guard let text = field.text, !text.isEmpty else {
return
}
let query = text.replacingOccurrences(of: " ", with: "%20")
movies.removeAll()
URLSession.shared.dataTask(with: URL(string: "https://www.omdbapi.com/?apikey=3aea79ac&s=\(query)&type=movie")!,
completionHandler: { data, response, error in
guard let data = data, error == nil else {
return
}
// Convert
var result: MovieResult?
do {
result = try JSONDecoder().decode(MovieResult.self, from: data)
}
catch {
print("error")
}
guard let finalResult = result else {
return
}
// Update our movies array
let newMovies = finalResult.Search
self.movies.append(contentsOf: newMovies)
// Refresh our table
DispatchQueue.main.async {
self.table.reloadData()
}
}).resume()
}
// Table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieTableViewCell.identifier, for: indexPath) as! MovieTableViewCell
cell.configure(with: movies[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Show movie details
if let vc = storyboard?.instantiateViewController(identifier: "detailViewController") as? detailViewController{
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
struct MovieResult: Codable {
let Search: [Movie]
}
struct Movie: Codable {
let Title: String
let Year: String
let imdbID: String
let _Type: String
let Poster: String
private enum CodingKeys: String, CodingKey {
case Title, Year, imdbID, _Type = "Type", Poster
}
}
MovieTableViewCell
class MovieTableViewCell: UITableViewCell {
#IBOutlet var movieTitleLabel: UILabel!
#IBOutlet var movieYearLabel: UILabel!
#IBOutlet var moviePosterImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
static let identifier = "MovieTableViewCell"
static func nib() -> UINib {
return UINib(nibName: "MovieTableViewCell",
bundle: nil)
}
func configure(with model: Movie) {
self.movieTitleLabel.text = model.Title
self.movieYearLabel.text = model.Year
let url = model.Poster
if let data = try? Data(contentsOf: URL(string: url)!) {
self.moviePosterImageView.image = UIImage(data: data)
}
}
}
DetailViewController
import UIKit
class detailViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLbl: UILabel!
#IBOutlet weak var yearLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
You can pass the data there when you create your UIViewController
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Show movie details
if let vc = storyboard?.instantiateViewController(identifier: "detailViewController") as? detailViewController{
vc.item = movies[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
But you need to pass data first, and when you controller initialized (loaded) you can assign value to loaded views
class detailViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLbl: UILabel!
#IBOutlet weak var yearLbl: UILabel!
var item: Movie? = nil
override func viewDidLoad() {
super.viewDidLoad()
if (let movie = item) {
titleLbl.text = item.title
yearLbl.tex = item.Year
// also image
}
}
}

Type 'HeroStruct.Type' cannot conform to 'Decodable', how can i solve that?

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var hero = [HeroStruct]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
navigationController?.navigationBar.barTintColor = UIColor.systemYellow
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.systemYellow ]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: nil)
cell.textLabel?.text = ""
cell.backgroundColor = .systemYellow
return cell
}
func getJsonData(completion: #escaping () -> () ) {
let url = URL(string: "https://api.opendota.com/api/heroStats")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
if error != nil {
print(error?.localizedDescription)
}else {
do {
let result = try JSONDecoder().decode(HeroStruct.Type, from: data!)
}catch {
print(error)
}
}
}
}
}
import Foundation
struct HeroStruct : Decodable {
let localized_name : String
let primary_attr : String
let attack_type : String
let legs : Int
let img : String
}
First code block is my ViewController.swift page,
second code block is my HeroStruct.swift page,
I tried to get data from Json but i got error like this:
Type 'HeroStruct.Type' cannot conform to 'Decodable'
How can i solve this?
let result = try JSONDecoder().decode([HeroStruct].Type, from: data!)`
I tried write like this but doesn't work. Need help ,thanks.
Replace [HeroStruct].Type with [HeroStruct].self. Whenever you want to decode something, always use .self & not .Type.

I can't print to TableView data with Swift JSON

I'm new to using JSON and wanted to start with a simple app to provide an overview of the movie. The following code does not print anything on the tableView, the app remains empty, with no results. He makes no mistakes. In the debug area, however, the data prints them to me. How can I get the results on the tableView?
ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var popularMoviesArray = [Results]()
var swiftManager = SwiftManager()
var tableViewCell = TableViewCell()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var labelError: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
swiftManager.delegate = self
swiftManager.fetchUrl()
self.tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return popularMoviesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let item = popularMoviesArray[indexPath.row]
cell.labelTitle.text = item.title
cell.labelYear.text = item.release_date
cell.labelRate.text = String(item.vote_average ?? 0.0)
cell.labelOreview.text = item.overview
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToDetail", sender: indexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier != nil else {
return
}
let letRow = sender as? Int
switch segue.identifier {
case "goToDetail":
(segue.destination as! ViewControllerDetail).itemDetail = popularMoviesArray[letRow!]
default:
return
}
}
}
extension ViewController: SwiftManagerDelegate {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.popularMoviesArray = swiftData.results
print("PRINT ARRAY - \(self.popularMoviesArray)")
}
}
func didFailWithError(error: Error) {
print(error)
}
}
You have to reload the table view in the delegate method because the data is loaded asynchronously
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.popularMoviesArray = swiftData.results
self.tableView.reloadData()
print("PRINT ARRAY - \(self.popularMoviesArray)")
}
}
Reloading the table view in viewDidLoad is pointless.

How to send data to table view with Alamofire And SwiftyJSON

I have a (large amount) of data that I want to send to Table View with alamofire and siftyJSON
web request :
let postEndPoint :String = "http://jsonplaceholder.typicode.com/posts/"
code Alamofire and SwiftyJSON:
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, postEndPoint).responseJSON { response in
// handle json
guard response.result.error == nil else{
print("error calling Get on /posts/1")
print(response.result.error)
return
}
if let value: AnyObject = response.result.value{
let post = JSON(value)
// for i in 0...post.count{
if let title = post["data"].arrayValue as? [JSON]{
self.datas = title
self.tableView.reloadData()
print("the title is :\(title)" )
}else{
print("eror parsing /post/1 ")
}
// }
}
}
}
code table view :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell")!
var dict = datas[indexPath.row]
cell.textLabel?.text = dict["userId"] as? String
cell.detailTextLabel?.text = dict["id"] as? String
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datas.count
}
}
web request :enter link description here
I am trying to post some json data to table view but when I send the data it returns nothing . why??
this is the code working for me. main thing is you have to reload the table at the end of api calling. and you are printing nuber as a string so you have to convert it to string
my code is here
import UIKit
class customcell: UITableViewCell {
#IBOutlet weak var lbl1: UILabel!
#IBOutlet weak var lbl2: UILabel!
}
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tabledata: UITableView!
let postEndPoint :String = "http://jsonplaceholder.typicode.com/posts/"
var arr:NSMutableArray = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
web()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("customcell") as! customcell
let dict = arr[indexPath.row] as! NSDictionary
print(dict)
print(dict["userId"])
cell.lbl1?.text = String (dict["userId"]! )
cell.lbl2?.text = String (dict["id"]! )
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
func web()
{
request(.GET, postEndPoint, parameters: nil, encoding:
.JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
print(response.result.value)
if (response.result.value != nil)
{
self.arr = (response.result.value) as! NSMutableArray
}
self.tabledata.reloadData()
}
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (tableView == tabledata)
{
let cell = tableView.dequeueReusableCellWithIdentifier("customcell") as! customcell
let dict = arr[indexPath.row] as! NSDictionary
cell.lbl1?.text = String (dict["userId"]! )
cell.selectionStyle = .None
return cell
}
else if(tableView == tablefactoryoption)
{
let cell1:Facturyoptioncell = tableView.dequeueReusableCellWithIdentifier("Facturyoptioncell") as! Facturyoptioncell
let dict = arr[indexPath.row] as! NSDictionary
cell1.lbl2?.text = String (dict["Id"]! )
cell1.selectionStyle = .None
cell1.selectionStyle = .None
return cell1
}
else
{
let cell2:Technicalcell = tableView.dequeueReusableCellWithIdentifier("Technicalcell") as! Technicalcell
let dict = arr[indexPath.row] as! NSDictionary
cell2.lbl3?.text = String (dict["userId"]! )
return cell2
}
}
This is how you can use multiple tableview for display data.

data passing and using json data from alamofire with swift

I integrated alamofire, but I got one problem to use data within server communication.
Before I tell about my problem I will show my code:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var MainViewTable: UITableView!
#IBOutlet weak var SidesOpen: UIBarButtonItem!
#IBOutlet weak var GroupButton: UIButton!
var apps:[sample] = [sample]()
override func viewDidLoad() {
super.viewDidLoad()
SidesOpen.target = self.revealViewController()
SidesOpen.action = Selector("revealToggle:")
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.setUpSample()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setUpSample() {
Alamofire.request(.GET, "http://{url}").responseJSON{ (request, response, data, error) in
var json = JSON(data!)
for var index = 0; index < json["store"].count; ++index{
var marketinfo = json["store"][index]["name"].stringValue
var imageUrl = json["store"][index]["img"].stringValue
let sample_menu = sample(marketInfo: marketinfo, imageName: imageUrl, button: "")
self.apps.append(sample_menu)
}
}
print(self.apps)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return apps.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print(setUpSample())
let cell: TblCell = tableView.dequeueReusableCellWithIdentifier("marketCell") as! TblCell
let sample = apps[indexPath.row]
cell.setCell(sample.marketInfo , imageName: sample.imageName, Coupon: "s/t.jpeg")
return cell
}
}
Within setUpSample function I have got one problem that I have no idea to passing or taking out JSON data. In the function I tried to print result what I can have from it however, the result was empty.