I'm facing an error with parisng a JSON.
I can see that I have type mismatch however I'm not sure how to fix it:
typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
var dataModel = [Model]()
This is my model:
import Foundation
struct Model: Codable {
let basepath: String
let items: [Item]
}
struct Item: Codable {
let title: String
let abstract: String
let thumbnail: String
}
And this is my root view controller within which I'm parsing JSON.
import UIKit
class ViewController: UIViewController {
private let hostingView = UIView()
let cellID = "cell"
var dataModel = [Country]()
let tableView: UITableView = {
let table = UITableView()
table.rowHeight = 100
table.translatesAutoresizingMaskIntoConstraints = false
return table
}()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.showSpinner(on: hostingView)
}
override func viewDidLoad() {
super.viewDidLoad()
configureView()
configureConstraints()
tableView.delegate = self
tableView.dataSource = self
tableView.register(TableViewCell.self, forCellReuseIdentifier: cellID)
performRequest()
}
private func configureView(){
view.backgroundColor = .white
title = "Game Of Thrones"
navigationController?.navigationBar.prefersLargeTitles = true
}
private func configureConstraints(){
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
private func performRequest(){
let url = "https://gameofthrones.fandom.com/api/v1/Articles/Top?expand=1&category=Articles&limit=75"
let urlString = URL(string: url)
guard urlString != nil else {return}
print(String("URL: \(urlString)"))
let session = URLSession(configuration: .default)
let dataTask = session.dataTask(with: urlString!) { (data, response, error) in
if error == nil && data != nil {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode([Country].self, from: data!)
self.dataModel = decodedData
print(self.dataModel)
DispatchQueue.main.async {
self.removeSpinner()
self.tableView.reloadData()
}
} catch {
DispatchQueue.main.async {
print(error)
self.performRequestError()
}
}
}
}
dataTask.resume()
}
private func performRequestError(){
let ac = UIAlertController(title: "Error", message: "Cannot load data", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(ac, animated: true)
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if dataModel.count > 0 {
// return dataModel[0].items.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! TableViewCell
cell.textLabel?.text = "title"
return cell
}
}
My project contains collectionView.. but how to push different viewcontroller from didSelectItemAt based on json id.. and i have separate vewcontrollers for each id.. but i am unable to push different viewcontrolls with didSelectItemAt based on json id.
here is my Json for collectionView:
{
"financer": [
{
"id": "45",
"icon": "https://hello.com//images/img1.png"
}
{
"id": "40",
"icon": "https://hello.com//images/img2.png"
}
.
.
.
]
}
here is my home collectionview code:
import UIKit
struct JsonData {
var iconHome: String?
init(icon: String, tpe: String) {
self.iconHome = icon
}
}
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
var itemsArray = [JsonData]()
var idArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
homeServiceCall()
//Do any additional setup after loading the view.
collectionView.delegate = self
collectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemsArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HomeCollectionViewCell
let aData = itemsArray[indexPath.row]
cell.paymentLabel.text = aData.typeName
if let url = NSURL(string: aData.iconHome ?? "") {
if let data = NSData(contentsOf: url as URL) {
cell.paymentImage.image = UIImage(data: data as Data)
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "MakePaymentViewController") as! MakePaymentViewController
self.navigationController?.pushViewController(nextViewController, animated: true)
let indexPathHome = indexPath.row
print("home collectionItem indexpath \(indexPathHome)")
}
//MARK:- Service-call
func homeServiceCall(){
let urlStr = "https://dev.com/webservices/getfinancer"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
let financerArray = jsonObj["financer"] as! [[String: Any]]
for financer in financerArray {
let id = financer["id"] as! String
let pic = financer["icon"] as? String
print("home financer id \(id)")
self.idArray.append(id)
print("the home financer idsArray \(self.idArray.append(id))")
self.itemsArray.append(JsonData(icon: pic ?? ""))
}
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
catch {
print("catch error")
}
}).resume()
}
}
when I click on any item from collectionview i am able to push same view controller but i need to push different view controller based on json id. i dont know how to and where to use json id to push differnt viewcontroller using didselectItem atIndexPath. anyone please help me here.
Update your homeServiceCall function
func homeServiceCall(){
let urlStr = "https://dev.com/webservices/getfinancer"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
let financerArray = jsonObj["financer"] as! [[String: Any]]
for financer in financerArray {
let id = financer["id"] as! String
let pic = financer["icon"] as? String
self.itemsArray.append(JsonData(icon: pic ?? ""))
self.idArray.append(id)
}
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
catch {
print("catch error")
}
}).resume()
}
Create a string property called financerId in your MakePaymentViewController
In your didSelect function
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "MakePaymentViewController") as? MakePaymentViewController {
nextViewController.finacerId = idArray[indexPath.row]
self.navigationController?.pushViewController(nextViewController, animated: true)
}
}
Update
for financer in financerArray {
if let id = financer["id"] as? Int {
self.idArray.append(id)
}
if let pic = financer["icon"] as? String {
elf.itemsArray.append(JsonData(icon: pic))
}
}
I have a problem in my project. When I filter the data (name and code) in the tableview of json and I select that data, the contents (code) data is different with the name of the select. Have I made an error?
Here is JSON:
}
"project": [
{
"name": "IT and Digital",
"code": “001”,
},
{
"name": "Business Solution",
"code": “002”,
}
}
I use two viewcontroller. viewcontroller1 to display a list of project names and viewcontroller2 to display project details (name and code)
var arrName = [String]()
var arrCode = [String]()
var filterMyProject = [String]()
var myIndexPro = 0
var myIndexFilterPro = 0
var isFilterPro = false
ViewController1:
let url = URL(string: apiServer)
URLSession.shared.dataTask(with: url!) {(data, response, error) in
if error != nil {
return
}else{
guard data != nil else {return}
do {
arrName.removeAll()
arrCode.removeAll()
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
if let itemProject = json?["project"] as? [[String: Any]] {
for items in itemProject {
let name = items["name"] as! String
let code = items["code"] as! String
arrName.append(name)
arrCode.append(code)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print(error)
}
}
}.resume()
func updateSearchResults(for searchController: UISearchController) {
filterMyProject = arrName.filter { (tproject: String) -> Bool in
if tproject.lowercased().contains(self.searchController.searchBar.text!.lowercased()) {
return true
}else{
return false
}
}
resultsController.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = self.tableView.indexPathForSelectedRow
let indexPath2 = resultsController.tableView.indexPathForSelectedRow
if tableView == resultsController.tableView {
isFilterPro = true
myIndexFilterPro = (indexPath2?.row)!
}else{
isFilterPro = false
myIndexPro = (indexPath?.row)!
}
performSegue(withIdentifier: "listprojectSegue", sender: nil)
}
ViewController2:
override func viewDidLoad() {
super.viewDidLoad()
if isFilterPro == false {
labelListProject.text = arrName[myIndexPro]
labelCode.text = arrCode[myIndexPro]
print("Code: " + code)
}else{
labelListProject.text = filterMyProject[myIndexFilterPro]
labelCode.text = arrCode[myIndexFilterPro]
print("Code Filter: " + code)
}
}
I'm using the YouTube API and Alamofire to show videos for my YouTube channel. I'm having an issue that the thumbnails for the videos are messing up when scrolling. Like this:
I used Apple videos for the example. For some reason, the colors got messed up when creating the GIF, though. But you get the idea. Here are my relevant view controllers
TableViewController
import UIKit
class VideosTableViewController: UITableViewController, VideoModelDelegate {
var videos: [Video] = [Video]()
var selectedVideo:Video?
let model:VideoModel = VideoModel()
override func viewDidLoad() {
super.viewDidLoad()
if tableView.rowHeight == 250 {
tableView.estimatedRowHeight = 250
} else {
tableView.estimatedRowHeight = 96
}
tableView.rowHeight = UITableViewAutomaticDimension
model.getFeedVideo()
self.model.delegate = self
dataReady()
//
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func handleRefresh() {
dataReady()
refreshControl?.endRefreshing()
}
func dataReady() {
print("dataReady()")
self.videos = self.model.videoArray
self.tableView.reloadData()
}
// 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
return videos.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
if indexPath.row == 0 {
var cell : NewVideoTableViewCell! = tableView.dequeueReusableCell(withIdentifier: "New Cell") as! NewVideoTableViewCell
cell.titleLabel.text = videos[indexPath.row].videoTitle
cell.thumbnail.clipsToBounds = true
cell.thumbnail.layer.cornerRadius = 5
let videoThumbnailURLString = videos[indexPath.row].videoThumbnailUrl
let videoThumbnailUrl = NSURL(string: videoThumbnailURLString)
if videoThumbnailUrl != nil {
let request = NSURLRequest(url: videoThumbnailUrl! as URL)
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
DispatchQueue.main.async {
cell.thumbnail.image = UIImage(data: data!)
}
})
dataTask.resume()
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let videoTitle = videos[indexPath.row].videoTitle
let title = cell.viewWithTag(2) as! UILabel
title.text = videoTitle
let videoThumbnailURLString = videos[indexPath.row].videoThumbnailUrl
let videoThumbnailUrl = NSURL(string: videoThumbnailURLString)
let imageView = cell.viewWithTag(1) as! UIImageView
if videoThumbnailUrl != nil {
let request = NSURLRequest(url: videoThumbnailUrl! as URL)
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
let imageView = cell.viewWithTag(1) as! UIImageView
DispatchQueue.main.async {
imageView.image = UIImage(data: data!)
}
})
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 3
imageView.layer.borderColor = UIColor.lightGray.cgColor
imageView.layer.borderWidth = 0.1
dataTask.resume()
}
return cell
}
}
}
VideoModel
import UIKit
import Alamofire
protocol VideoModelDelegate {
func dataReady()
}
let API_KEY = "My API Key"
let UPLOADS_PLAYLIST_ID = "My Playlist"
let CHANNEL_ID = "My Channel ID"
let parameters = ["part":"snippet","maxResults":50,"channelId":CHANNEL_ID,"playlistId":UPLOADS_PLAYLIST_ID,"key":API_KEY] as [String : Any]
class VideoModel: NSObject {
var videoArray = [Video]()
var delegate: VideoModelDelegate?
func getFeedVideo() {
Alamofire.request("https://www.googleapis.com/youtube/v3/playlistItems", parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
if let JSON = response.result.value {
if let dictionary = JSON as? [String: Any] {
var arrayOfVideos = [Video]()
guard let items = dictionary["items"] as? NSArray else { return }
for items in dictionary["items"] as! NSArray {
print(items)
// Create video objects off of the JSON response
let videoObj = Video()
videoObj.videoID = (items as AnyObject).value(forKeyPath: "snippet.resourceId.videoId") as! String
videoObj.videoTitle = (items as AnyObject).value(forKeyPath: "snippet.title") as! String
videoObj.videoDescription = (items as AnyObject).value(forKeyPath: "snippet.description") as! String
videoObj.videoThumbnailUrl = (items as AnyObject).value(forKeyPath: "snippet.thumbnails.maxres.url") as! String
arrayOfVideos.append(videoObj)
}
self.videoArray = arrayOfVideos
if self.delegate != nil {
self.delegate!.dataReady()
}
}
}
}
}
Video
import UIKit
class Video: NSObject {
var videoID:String = ""
var videoTitle:String = ""
var videoDescription:String = ""
var videoThumbnailUrl:String = ""
}
So, do you see how the thumbnails get are jumpy? Any ideas? Thanks for the help!
if statusCode == 200 {
let json = response.result.value as? NSDictionary
print("JSON FILE")
//print(json)
let companies = json?["companies"] as? [AnyObject]
print(companies)
for value in companies! {
let address = value["address"] as? String
print(address)
let schedule = companies?["schedule"] as? [AnyObject]// as? NSDictionary
print(schedule)
for sch in schedule! {
}
}
}
Here json file
{
"code": "200",
"message": "OK",
"companies": [
{
"id": "1",
"img": "doxsun.jpg",
"schedule": [
{
"id": "1",
"company_id": "1",
"day": "0",
"time_from": "06:00:00",
"time_to": "23:00:00"
}
]
},
{
"id": "2",
"img": "zalypa.jpg",
"schedule": []
}
]
}
I have a problem with json file parsing how correctly parse it? I can't parse schedule. How to convert all this types? words to pass quality. words to pass quality.words to pass quality.words to pass quality.words to pass quality.words to pass quality.words to pass quality.words to pass quality.words to pass quality.words to pass quality.
There are some conversion issues with correct types using as operator. I believe the below code should allow you to iterate through schedules of each company:
if let JSON = response.result.value as? [String: AnyObject] {
if let companies = JSON["companies"] as? [[String: AnyObject]] {
for company in companies {
if let schedules = company["schedule"] as? [[String: AnyObject]] {
for schedule in schedules {
// do something with the schedule
}
}
}
}
}
extension ViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return 2 //datamodel.count
return newarr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: tblCell.identifier, for: indexPath) as! tblCell
self.json = newarr.object(at: indexPath.row) as! NSDictionary
cell.lblName.text = json.value(forKey: "artistName") as? String
return cell
}
}
extension ViewController {
func swiftyJson(){
let url = URL(string: "https://itunes.apple.com/search?term=jack+johnson")
//let url = URL(string: "http://makani.bitstaging.in/api/business/businesses_list")
Alamofire.request(url!, method: .get, parameters: nil).responseJSON { response in
switch(response.result) {
case .success(_):
let data = response.result.value as! NSDictionary
self.newarr = data.value(forKey: "results")as! NSArray
print(self.newarr)
self.tblView.reloadData()
break
case .failure(_):
print(response.result.error as Any)
break
}
}
}
}
let url = URL(string: "https://api.androidhive.info/contacts")
Alamofire.request(url!, method: .get, parameters: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let dicData = response.result.value as? [String : Any]{
if let arrOfCartDetails = Mapper<BaseDataModel>().map(JSON: dicData) {
self.arrData.append(arrOfCartDetails)
print(self.arrData)
if self.arrData.count > 0{
self.arrContect = self.arrData[0].contacts!
print(self.arrContect[0].phone?.home)
}
if self.arrContect.count > 0{
self.tblDemo.reloadData()
}
}
break
case .failure(_):
print(response.result.error as Any)
break
}
}
let url = URL(string: "https://jsonplaceholder.typicode.com/todos")
Alamofire.request(url!, method: .get, parameters: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let data = response.result.value as? [[String : Any]]{
if Mapper<DocumentDataModel>().mapArray(JSONArray: data).count > 0{
self.arrDataModel = Mapper<DocumentDataModel>().mapArray(JSONArray: data)
print(self.arrDataModel)
let banner = self.arrDataModel[0]
print("userId", banner.userId)
if self.arrDataModel.count > 0{
self.tblDemo.reloadData()
}
}
}
break
case .failure(_):
print(response.result.error as Any)
break
}
}
let url = "https://reqres.in/api/products"
AF.request(url, method: .get, parameters: nil).responseJSON{ (response) in
switch(response.result) {
case .success(let responseString):
print("Success")
// print(responseString)
let User = Mapper<Response>().map(JSONObject:responseString)
// print(User)
self.arrayFavouriteJobList = (User?.data)!
print(self.arrayFavouriteJobList)
self.tblData.reloadData()
break
case .failure(_):
print(response.error as Any)
break
}
}
func apiCalling(){
let url = "https://jsonplaceholder.typicode.com/posts"
AF.request(url, method: .get, parameters: nil, headers: nil).responseJSON { (response) in
if let responseData = response.data{
print(response)
do{
let decodeJson = JSONDecoder()
decodeJson.keyDecodingStrategy = .convertFromSnakeCase
self.responseData = try decodeJson.decode([DataModel].self, from: responseData)
self.tblData.reloadData()
}catch{
}
}
}
}
Alamofire.request(url, method: .get, headers: nil).responseJSON{response in
switch response.result{
case.success:
print("sucess")
if let JSON = response.result.value
{
self.hk = JSON as! NSDictionary
print(self.hk)
print(((self.hk.value(forKey: "contacts")as! NSArray).object(at: 4 )as! NSDictionary).value(forKey: "name")as! NSString)
self.flag = 1
self.tbl1.reloadData()
}
case.failure(let Error):
print("error\(Error)")
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if flag == 0
{
return 0
}
else
{
return (self.hk.value(forKey: "contacts")as! NSArray).count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tbl1.dequeueReusableCell(withIdentifier: "cell", for: indexPath)as! TableViewCell1
cell.lbl1.text = (((self.hk.value(forKey: "contacts")as! NSArray).object(at: indexPath.row)as! NSDictionary).value(forKey: "name")as!String)
return cell
}
class ViewController: UIViewController, UITableViewDelegate,UITableViewDataSource{
var hk : NSDictionary = NSDictionary()
let url = "https://itunes.apple.com/search?term=jack+johnson"
#IBOutlet var tblview: UITableView!
var flag = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
getdata()
}
func getdata()
{
//let url = "https://itunes.apple.com/search?term=jack+johnson"
Alamofire.request(url, method: .get, headers: nil).responseJSON{response in
switch response.result{
case.success:
print("sucess")
if let JSON = response.result.value
{
self.hk = JSON as! NSDictionary
print(self.hk)
print(((self.hk.value(forKey: "results")as! NSArray).object(at: 0)as! NSDictionary).value(forKey: "artworkUrl60")as! NSString)
//print(((self.hk.value(forKey: "contacts")as! NSArray).object(at: 4 )as! NSDictionary).value(forKey: "name")as! NSString)
self.flag = 1
self.tblview.reloadData()
}
case.failure(let Error):
print("error\(Error)")
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if flag == 0
{
return 0
}
else
{
return (self.hk.value(forKey: "results")as! NSArray).count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)as! TableViewCell1
let imageURL = NSURL(string: (((self.hk.value(forKey: "results")as! NSArray).object(at: indexPath.row) as! NSDictionary).value(forKey: "artworkUrl60") as! String))
let imagedData = NSData(contentsOf: imageURL! as URL)!
cell.img1.image = UIImage(data: imagedData as Data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let bh = storyboard?.instantiateViewController(withIdentifier: "imageViewController")as!imageViewController
bh.str = (((self.hk.value(forKey: "results")as! NSArray).object(at: indexPath.row) as! NSDictionary).value(forKey: "artworkUrl60") as! String)
self.navigationController?.pushViewController(bh, animated: true)
}
// swifty Json
func jsonParsing(){
let url = URL(string: "https://api.androidhive.info/contacts/")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let data = data else { return }
do{
let json = JSON(data:data)
let contacts = json["contacts"][5]["phone"].dictionaryValue
print(contacts)
}
catch{
print(error.localizedDescription)
}
}.resume()
}
func jsonParsing(){
let url = URL(string: "https://api.androidhive.info/contacts/")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let data = data else { return }
do{
let json = JSON(data:data)
let contacts = json["contacts"]
let name = contacts["name"]
for arr in contacts.arrayValue{
print(arr["name"])
}
//prinerrrr)
}
catch{
print(error.localizedDescription)
}
}.resume()
}
}