I am trying to parse a json and load it in the CustomTable, my json parsed successful but could not load the data in the UI, i tried adding test datas, and it displayed. So i guess it has to do with scoping. I have tried using other answers on the same question, but still it did not for work me
import UIKit
import Alamofire
import SwiftyJSON
class NewsViewController: UIViewController,
UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var newsPosts = [NewsPost]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getNewsPost()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = newsPosts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "NewsCell") as? NewsPostCell{
cell.configureCell(post: post)
return cell
}else{
let cell = NewsPostCell()
cell.configureCell(post: post)
return cell
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return newsPosts.count
}
func getNewsPost(){
Alamofire.request(URL_BASE + NEWS_URL).responseJSON { response in
let json = JSON(data: response.data!)
if let dict = json.dictionaryObject{
if let result = dict["data"] as? [NSDictionary]{
for data in result{
guard let title = data["title"] as? String else{
return print("title is nil")
}
guard let href = data["href"] as? String else{
return print("href is nil")
}
guard let image = data["image"] as? String else{
return print("image is nil")
}
guard let content = data["content"] as? String else{
return print("content is nil")
}
guard let _ = data["timestamp"] as? String else{
return print("timestamp is nil")
}
guard let type = data["type"] as? String else{
return print("type is nil")
}
print(type)
let post = NewsPost(title: title, href: href,
image: image, timestamp:
"1 day ago", content: content, type: type)
self.newsPosts.append(post)
}
self.tableView.reloadData()
}
}
}
}
}
You should test if your tableview is initialized when before you reload the data :
import UIKit
import Alamofire
import SwiftyJSON
class NewsViewController: UIViewController,
UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var newsPosts = [NewsPost]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getNewsPost()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = newsPosts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "NewsCell") as? NewsPostCell{
cell.configureCell(post: post)
return cell
}else{
let cell = NewsPostCell()
cell.configureCell(post: post)
return cell
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return newsPosts.count
}
func getNewsPost(){
Alamofire.request(URL_BASE + NEWS_URL).responseJSON { response in
let json = JSON(data: response.data!)
if let dict = json.dictionaryObject{
if let result = dict["data"] as? [NSDictionary]{
for data in result{
guard let title = data["title"] as? String else{
return print("title is nil")
}
guard let href = data["href"] as? String else{
return print("href is nil")
}
guard let image = data["image"] as? String else{
return print("image is nil")
}
guard let content = data["content"] as? String else{
return print("content is nil")
}
guard let _ = data["timestamp"] as? String else{
return print("timestamp is nil")
}
guard let type = data["type"] as? String else{
return print("type is nil")
}
print(type)
let post = NewsPost(title: title, href: href,
image: image, timestamp:
"1 day ago", content: content, type: type)
self.newsPosts.append(post)
}
if self.tableView != nil {
self.tableView.reloadData()
}
}
}
}
}
}
I guess the problem is when you're calling the gettingNewPost function. The reloadData() function is called right after didLoad, maybe you havent even get the data when you call the function to populate the table. Have you tried to log in the cellForRow function to see if isnt trying to access a nil array?
I finally found the issue, one of the guard is return nil, so it stop the execution of others, so i changed from using guard to the below
let title = data["title"] as? String ?? ""
let href = data["href"] as? String ?? ""
let image = data["image"] as? String ?? ""
let content = data["content"] as? String ?? ""
let type = data["type"] as? String ?? ""
Related
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()
}
Here i have created table view with labelName and labelUsername,
and i have downloaded Json data and saving it in core data entity called Details which contains attributes name and username..
here table view showing its data in online...
but how can i show fetched data in table view while in offline..
please help me in the code...
import UIKit
import CoreData
struct JsonData {
var nameS: String
var usernameS: String
init(name: String, username: String) {
self.nameS = name
self.usernameS = username
}
}
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var iteamsArray = [JsonData]()
override func viewDidLoad() {
downloadJson()
}
func downloadJson(){
let urlStr = "https://jsonplaceholder.typicode.com/users"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
guard error == nil else {
print("error")
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [[String: Any]]
for items in jsonObj {
let nameJson = items["name"] as? String
let usernameJson = items["username"] as? String
let coreData = NSEntityDescription.insertNewObject(forEntityName: "Details", into: self.context) as! Details
coreData.name = nameJson
coreData.username = usernameJson
self.iteamsArray.append(JsonData(name: nameJson!, username: usernameJson!))
}
try self.context.save()
//fetching from core data
let fetchRequest : NSFetchRequest<Details> = Details.fetchRequest()
let details = try self.context.fetch(fetchRequest)
if details.count > 0 {
for detail in details as [NSManagedObject] {
let nameCore = detail.value(forKey: "name")
let usernameCore = detail.value(forKey: "username")
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
catch {
print("catch error")
}
}).resume()
}
}
// MARK: - TableView
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return iteamsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "JsonCell", for: indexPath) as! JsonTableViewCell
let aData = iteamsArray[indexPath.row]
cell.labelName.text = aData.nameS
cell.labelUsername.text = aData.usernameS
cell.selectionStyle = .none
return cell
}
}
First of all forget the custom struct. Use the NSManagedObject class as data source array.
var iteamsArray = [Details]()
In viewDidLoad first fetch the data, if the array is empty load it from the web service
override func viewDidLoad() {
let fetchRequest : NSFetchRequest<Details> = Details.fetchRequest()
do {
iteamsArray = try self.context.fetch(fetchRequest)
if iteamsArray.isEmpty {
downloadJson()
} else {
self.tableView.reloadData()
}
} catch { print(error) }
}
In downloadJson() replace
self.iteamsArray.append(JsonData(name: nameJson!, username: usernameJson!))
with
self.iteamsArray.append(coreData)
and remove these lines
//fetching from core data
let fetchRequest : NSFetchRequest<Details> = Details.fetchRequest()
let details = try self.context.fetch(fetchRequest)
if details.count > 0 {
for detail in details as [NSManagedObject] {
let nameCore = detail.value(forKey: "name")
let usernameCore = detail.value(forKey: "username")
}
}
In cellForRow get the values directly from the NSManagedObject objects
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "JsonCell", for: indexPath) as! JsonTableViewCell
let aData = iteamsArray[indexPath.row]
cell.labelName.text = aData.name
cell.labelUsername.text = aData.userName
cell.selectionStyle = .none
return cell
}
I'm new to iOS development and I'm having a hard time populating a tableview embedded in a UIviewcontroller with json data.
''import UIKit
class
FirstViewController:UIViewController,UITableViewDataSource,UITableViewDelegate{
#IBOutlet weak var tableview: UITableView!
var TableData:Array< String > = Array < String >()
var valueToPass:String!
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.kaleidosblog.com/tutorial/tutorial.json")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstViewCell", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let countries_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let country_obj = countries_list[i] as? NSDictionary
{
if let country_name = country_obj["country"] as? String
{
if let country_code = country_obj["code"] as? String
{
TableData.append(country_name + " [" + country_code + "]")
}
}
}
}
}
DispatchQueue.main.async(execute: {self.do_table_refresh()})
}
func do_table_refresh()
{
tableview.reloadData()
}
}
you need to set tableView's dataSource and delegate to self.
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.
I have parsed a json string and i want to use it in a tableview. when i try to append the json string into an array the append method is not working. Here is the code that i have used. Can anyone help me with this?
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var userName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// 1
let urlAsString = "http://demo.codeofaninja.com/tutorials/json-example-with-php/index.php"
let url = NSURL(string: urlAsString)!
let urlSession = NSURLSession.sharedSession()
//2
let jsonQuery = urlSession.dataTaskWithURL(url, completionHandler: { data, response, error -> Void in
if (error != nil) {
print(error!.localizedDescription)
}
// 3
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
/*let err: NSError!
if (err != nil) {
print("JSON Error \(err.localizedDescription)")
}*/
// 4
//let fname: String! = jsonResult["firstname"] as! String
//let lname: String! = jsonResult["lastname"] as! String
//let usrname: String! = jsonResult["username"] as! String
dispatch_async(dispatch_get_main_queue(), {
if let users = jsonResult.objectForKey("Users") as? [[String:AnyObject]]
{
for user in users
{
print("First Name:")
print(user["firstname"]!)
print("Last Name:")
print(user["lastname"]!)
print("User Name:")
let nameUser = user["username"]! as! String
print(nameUser)
self.userName.append(nameUser)
print("***************")
}
}
//print(jsonResult["Users"]!)
//print(lname)
//print(usrname)
})
}
catch {
print("error");
}
})
jsonQuery.resume()
//self.userName.append("ganesh")
// 5
print(userName)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userName.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!
cell.textLabel?.text = userName[indexPath.row]
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
userName.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You are appending right in the array,Just call self.tableView.reloadData() to refresh table view at the end of dispatch to show the data in the tableView.
The append function works fine but you are filling the array in the background and never reloading the tableView when you have the data in the array
for user in users
{
if let nameUser = user["username"] as? String {
self.userName.append(nameUser)
}
}
self.tableView.reloadData()
Try this inside the if let users = jsonResult.objectForKey("Users") as? [[String:AnyObject]] block