I have a project which is trying to bring in data from a web url using alamofire. I am trying to bring in image and text but keep getting build failed. I am trying to add the data (image and text) to tags = 1 and 2. My code is below any help would be appreciated. I am fairly new to Swift. Thanks
SWIFT
import UIKit
import Alamofire
struct postinput {
let mainImage : UIImage!
let name : String!
}
class TableViewController: UITableViewController {
var postsinput = [postinput]()
var mainURL = "https://www.testJSON.com"
typealias JSONstandard = [String : AnyObject]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callAlamo(url: mainURL)
}
func callAlamo(url : String){
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts {
let title = post["title"] as! String
if let images = post["image"] as? JSONstandard {
let mainImageURL = URL(string: imageData["url"] as! String)
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
}
postsinput.append(postinput.init(mainImage: mainImage, name: name))
}
self.tableView.reloadData()
}
}
catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postsinput.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// cell?.textLabel?.text = titles[indexPath.row]
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = postsinput[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = postsinput[indexPath.row].name
return cell!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
JSON
{ posts: [ { id: “000000”, url: "/content/interview2”, date: "2016-11-03 09:01:41", modified: "2016-11-03 09:03:47", title: "An interview", image: "https://www.example.com/sites/default/files/oregood.jpeg", summary: { value: "<p>Latin text here</p> ", format: "filtered_html" } ]}
The following are the reasons for your build error are the following:
you added this line postsinput.append(postinput.init(mainImage: mainImage, name: name))
outside the context where mainImage is obtained. Based on the json, I believe that you are supposed to rewrite it like this.
if let imageUrl = post["image"] as? JSONstandard {
let mainImageURL = URL(string: imageUrl)
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title))
}
Even if you do that, the variables imageData and name are undefined. You should look into that.
Just a suggestion, do not force unwrap optionals. Use optional binding wherever possible.
Related
I have searched around to find an answer for my issue, but I had no luck. I'm new in coding, especially with Swift 3.0.
I'm trying to parse a YouTube playlist dynamically in a tableview using Alamofire cocoa pod in my project. My project contains: a viewcontroller called "videosViewController" which holds the tableview, a class called "Video", which holds the items I'm parsing from youtube API, and another class called "VideoModel" holds the method to pare those items. When I run my project the console parse the items successfully, but then the project crashes at the line of code:
for video in (data["items"] as? NSDictionary)!
with "Could not cast value of type '__NSArrayI' (0x10d2ebd88) to 'NSDictionary' (0x10d2ec288)." error as shown below
Project crash
Console details
And here the snippet of code I used:
videosViewController:
import UIKit
class videosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var videos:[Video] = [Video]()
var selectedVideo: Video?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let model = VideoModel()
model.fetchVideos()
self.tableView.dataSource = self
self.tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return (self.view.frame.size.width / 320) * 180
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BasicCell")!
let videoTitle = videos[indexPath.row].videoTitle
let label = cell.viewWithTag(2) as! UILabel
label.text = videoTitle
let videoThumbnailUrlString = "https://i1.ytimg.com/vi/" + videos[indexPath.row].videoId + "/maxresdefault.jpg"
let videoThumbnailUrl = NSURL(string: videoThumbnailUrlString)
if videoThumbnailUrl != nil {
let request = URLRequest(url: videoThumbnailUrl! as URL)
let session = URLSession.shared
let task = session.dataTask(with: request,
completionHandler: { (data:Data?,
response:URLResponse?,
error:Error?) -> Void in
DispatchQueue.main.async {
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = UIImage(data: data!)
}
})
task.resume()
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedVideo = self.videos[indexPath.row]
self.performSegue(withIdentifier: "goToDetail", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailView = segue.destination as! videoDetailViewController
detailView.selectedVideo = self.selectedVideo
}
}
The Video class:
import UIKit
class Video: NSObject {
var videoId:String = ""
var videoTitle:String = ""
var videoDescription:String = ""
var videoThumbnailURL = ""
}
And the VideoModel class:
import UIKit
import Alamofire
class VideoModel: NSObject {
let parameters: Parameters = ["part":"snippet","playlistId":"PLMRqhzcHGw1ZRUB86rmNqG15Sr5jV-2NU","key":"AIzaSyDdNXhz3H7ifXB-qfOVakz0Xps2Y-kP0R0"]
var videoArray = [Video]()
func fetchVideos() {
Alamofire.request("https://www.googleapis.com/youtube/v3/playlistItems", method: .get, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(let JSON):
print("Success with JSON: \(JSON)")
if let data = response.result.value as? [String: AnyObject] {
// print(response.result.value)
var arrayOfVideos = [Video]()
for video in (data["items"] as? NSDictionary)! {
let videoObj = Video()
videoObj.videoId = (video.value as? NSDictionary)?["snippet.resourceId.videoId"] as? String ?? ""
videoObj.videoTitle = (video.value as? NSDictionary)?["snippet.title"] as? String ?? ""
videoObj.videoDescription = (video.value as? NSDictionary)?["snippet.description"] as? String ?? ""
videoObj.videoThumbnailURL = (video.value as? NSDictionary)?["snippet.thumbnails.maxres.url"] as? String ?? ""
print(video)
// You need to parse the items into the video data
arrayOfVideos.append(videoObj)
}
self.videoArray = arrayOfVideos
// }
}
case .failure(let error):
print("Request failed with error: \(error)")
}
}
}
Replace
as? NSDictionary
with
as? [String:Any]
in
for video in (data["items"] as? NSDictionary)!
Bcs: You have to cast type Any to Swift dictionary type [String:Any].
if let JSON = response.result.value as? [String : Any] {
if let items = JSON["items"] as? [[String : Any]] {
for video in items {
//Other code
}
}
}
I am building my app in Swift 3 with Alamofire. I have JSON data coming into a list view. Every time I pull to refresh the content, instead of refreshing the content, it just adds more items to the bottom of the list in list view, instead of refreshing the visible list. I don't know what I could be doing wrong, my code so far is:
import UIKit
import Alamofire
import SVProgressHUD
struct postinput {
let mainImage : UIImage!
let name : String!
let author : String!
let summary : String!
let content : String!
}
class TableViewController: UITableViewController {
//var activityIndicatorView: UIActivityIndicatorView!
var postsinput = [postinput]()
var refresh = UIRefreshControl()
var mainURL = "https://www.example.com/api"
typealias JSONstandard = [String : AnyObject]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.separatorStyle = UITableViewCellSeparatorStyle.none
self.tableView.addSubview(refresh)
//;refresh.attributedTitle = NSAttributedString(string: "Refreshing...", attributes:[NSForegroundColorAttributeName : UIColor.black])
refresh.backgroundColor = UIColor(red:0.93, green:0.93, blue:0.93, alpha:1.0)
//refresh.tintColor = UIColor.white
refresh.addTarget(self, action: #selector(self.refreshData), for: UIControlEvents.valueChanged)
//refresh.addTarget(self, action: #selector(getter: TableViewController.refresh), for: UIControlEvents.valueChanged)
refresh.attributedTitle = NSAttributedString(string: "Updated: \(NSDate())")
//activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
//tableView.backgroundView = activityIndicatorView
callAlamo(url: mainURL)
}
func refreshData() {
Alamofire.request("https://www.example.com/api").responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.singleLine
DispatchQueue.main.async {
self.tableView.reloadData()
self.refresh.endRefreshing()
}
})
}
func callAlamo(url : String){
//activityIndicatorView.startAnimating()
SVProgressHUD.show(withStatus: "Loading...")
SVProgressHUD.setDefaultStyle(SVProgressHUDStyle.dark)
SVProgressHUD.setDefaultAnimationType(SVProgressHUDAnimationType.native)
SVProgressHUD.setDefaultMaskType(SVProgressHUDMaskType.black)
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.singleLine
//self.activityIndicatorView.stopAnimating()
SVProgressHUD.dismiss()
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
// print(readableJSON)
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts {
let title = post["title"] as! String
let author = post["author"] as! String
guard let dic = post["summary"] as? [String: Any], let summary = dic["value"] as? String else {
return
}
let str = summary.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
print(str)
guard let dic1 = post["content"] as? [String: Any], let content = dic1["value"] as? String else {
return
}
let str1 = content.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
print(str1)
//print(author)
if let imageUrl = post["image"] as? String {
let mainImageURL = URL(string: imageUrl )
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title, author: author, summary: summary, content: content))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postsinput.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// cell?.textLabel?.text = titles[indexPath.row]
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = postsinput[indexPath.row].mainImage
mainImageView.layer.cornerRadius = 5.0
mainImageView.clipsToBounds = true
//(cell?.viewWithTag(2) as! UIImageView).image = postsinput[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = postsinput[indexPath.row].name
mainLabel.font = UIFont.boldSystemFont(ofSize: 18)
mainLabel.sizeToFit()
mainLabel.numberOfLines = 0;
let autLabel = cell?.viewWithTag(3) as! UILabel
autLabel.text = postsinput[indexPath.row].author
autLabel.font = UIFont(name: "Helvetica", size:16)
autLabel.textColor = UIColor(red: 0.8784, green: 0, blue: 0.1373, alpha: 1.0) /* #e00023 */
let sumLabel = cell?.viewWithTag(4) as! UILabel
sumLabel.text = (postsinput[indexPath.row].summary).replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
sumLabel.font = UIFont(name: "Helvetica", size:16)
sumLabel.textColor = UIColor(red:0.27, green:0.27, blue:0.27, alpha:1.0)
//let contentLabel = cell?.viewWithTag(0) as! UILabel
//contentLabel.text = (postsinput[indexPath.row].content).replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
//(cell?.viewWithTag(3) as! UILabel).text = postsinput[indexPath.row].author
return cell!
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
SVProgressHUD.show()
let indexPath = self.tableView.indexPathForSelectedRow?.row
let vc = segue.destination as! nextVC
vc.articleImage = postsinput[indexPath!].mainImage
vc.articleMainTitle = postsinput[indexPath!].name
vc.articleContent = postsinput[indexPath!].content
SVProgressHUD.dismiss()
let backItem = UIBarButtonItem()
backItem.title = "Back"
navigationItem.backBarButtonItem = backItem // This will show in the next view controller being pushed
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
postsinput.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your issue is here:
postsinput.append(postinput.init(mainImage: mainImage, name: title, author: author, summary: summary, content: content))
You keep appending new data to the old data. If you want to completely clear out the old data before adding new data, just remove all of the elements from the postsinput array.
Your task here in pull to refresh is to just refresh the data existing in your list and also add the new items if any. So what you have to do is instead of keep on adding the items to your list everytime you pull-to-refresh, you just provide a new list coming from server to your tableView. Which you have the array aleready postsinput so make sure to remove all the items before you add it. Below is your code where you can do the changes.
func parseData(JSONData : Data) {
postsinput.removeAll()
do {
...
...
if let imageUrl = post["image"] as? String {
let mainImageURL = URL(string: imageUrl )
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title, author: author, summary: summary, content: content))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
...
...
}
I'm trying to populate a table view with data fetched from a http request (JSON) but it's not working. If I populate the Table View with static data everything works fine.. code snippet:
import UIKit
import Alamofire
//import SwiftyJSON
class ViewControllerNews : UITableViewController{
#IBOutlet var table: UITableView!
var posts = [FacebookPost]()
override func viewDidLoad() {
pullFacebookNews()
//loadSampleNews()
super.viewDidLoad()
}
func pullFacebookNews() -> Void {
let params = ["limit":"100", "access_token": myaccesstoken]
Alamofire.request( "https://graph.facebook.com/<page-id>/posts", parameters: params).responseJSON{ response in
if let responsejson = response.result.value {
let JSON = responsejson as! NSDictionary
let itemsArray: NSArray? = JSON.object(forKey: "data") as? NSArray
if(itemsArray != nil) {
for item in itemsArray! {
let thisitem = item as! NSDictionary
print(thisitem.object(forKey: "message") as? String)
print(thisitem.object(forKey:"created_time") as? String)
let title1 = thisitem.object(forKey: "message") as? String
let value1=thisitem.object(forKey:"created_time") as? String
if(title1 != nil && value1 != nil) {
let news = FacebookPost(title: title1!, value: value1!)
self.posts.append(news)
}
}}
}
}
do_table_refresh()
}
func do_table_refresh() {
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
self.table.reloadData()
}
}
}
func loadSampleNews() {
let news1 = FacebookPost(title: "ich bin ein datum", value: "Ich bin eine news")
let news2 = FacebookPost(title: "ich bin ein datum2", value: "Ich bin eine news2")
let news3 = FacebookPost(title: "ich bin ein datum3", value: "Ich bin eine news3")
posts += [news1, news2, news3]
}
override func numberOfSections(in: UITableView) -> Int {
return 1
}
override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_: UITableView, cellForRowAt: IndexPath) -> UITableViewCell {
let cellIdentifier = "NewsTableViewCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: cellForRowAt as IndexPath) as! NewsTableViewCell
let news = posts[cellForRowAt.row]
cell.date.text = news.title
cell.news_text.text = news.value
return cell
}
}
The loadSampeNews() works perfectly, but pullFacebookNews() does not populate the table. While debugging the array is filled..
If you set breakpoints, you will see that do_table_refresh() gets called before you hit if let responsejson = response.result.value. This is because the Alamofire call has a completion handler. You have to wait until the internet call is complete before you call do_table_refresh().
So you essentially just have to move do_table_refresh() if all of your data is loading correctly like you say it is.
func pullFacebookNews() -> Void {
let params = ["limit":"100", "access_token": myaccesstoken]
Alamofire.request( "https://graph.facebook.com/<page-id>/posts", parameters: params).responseJSON{ response in
if let responsejson = response.result.value {
let JSON = responsejson as! NSDictionary
let itemsArray: NSArray? = JSON.object(forKey: "data") as? NSArray
if(itemsArray != nil) {
for item in itemsArray! {
let thisitem = item as! NSDictionary
print(thisitem.object(forKey: "message") as? String)
print(thisitem.object(forKey:"created_time") as? String)
let title1 = thisitem.object(forKey: "message") as? String
let value1=thisitem.object(forKey:"created_time") as? String
if(title1 != nil && value1 != nil) {
let news = FacebookPost(title: title1!, value: value1!)
self.posts.append(news)
}
}
}
self.do_table_refresh()
}
}
}
Additionally, don't name your methods with that syntax. It is not best practice. Should be doTableRefresh() or something.
I have an app that is using Swift 3 and Alamofire. The data is connected to two cell?.viewWithTag(2) and cell?.viewWithTag(1) which is an image (from url) and text. So when I run the project nothing is showing in my App. I have tested the JSON with print(readableJSON) and the JSON is getting printed into the console. So I am a little confused really. My swift looks like this:
SWIFT
import UIKit
import Alamofire
struct postinput {
let mainImage : UIImage!
let name : String!
}
class TableViewController: UITableViewController {
var postsinput = [postinput]()
var mainURL = "https://www.example.api.com"
typealias JSONstandard = [String : AnyObject]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callAlamo(url: mainURL)
}
func callAlamo(url : String){
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
print(readableJSON)
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts {
let title = post["title"] as! String
print(title)
if let imageUrl = post["image"] as? JSONstandard {
let mainImageURL = URL(string: imageUrl["url"] as! String)
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title))
self.tableView.reloadData()
}
}
}
}
catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postsinput.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// cell?.textLabel?.text = titles[indexPath.row]
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = postsinput[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = postsinput[indexPath.row].name
return cell!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
JSON
{
"posts" : [{
"id": "000000",
"url": "/content/interview2",
"date": "2016-11-03 09:01:41",
"modified": "2016-11-03 09:03:47",
"title": "An interview",
"image": "https://www.example.com/sites/default/files/oregood.jpeg",
"summary": {
"value": "<p>Latin text here</p>",
"format": "filtered_html"
}
}]
}
From your JSON response image key contains String not Dictionary also you need to reload your tableView outside for loop not every time inside the loop, so try like this.
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts {
let title = post["title"] as! String
if let imageUrl = post["image"] as? String {
let mainImageURL = URL(string: imageUrl as! String)
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Suggestion : Instead of downloading image using NSData(contentsOf:) on main thread batter to use library like SDWebImages or you can create your own async image downloader.
because you are not displaying your JSON in table cells. You crate a copied object called "mainImageView" and never assign it as actual imageView of table cell, instead try:
(cell?.viewWithTag(2) as? UIImageView).image = postsinput[indexPath.row].mainImage
postsinput contains image strings or images?
EDIT:
so it would be:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// cell?.textLabel?.text = titles[indexPath.row]
//let mainImageView = cell?.viewWithTag(2) as! UIImageView
//mainImageView.image = postsinput[indexPath.row].mainImage
(cell?.viewWithTag(2) as? UIImageView).image = postsinput[indexPath.row].mainImage
//let mainLabel = cell?.viewWithTag(1) as! UILabel
//mainLabel.text = postsinput[indexPath.row].name
(cell?.viewWithTag(1) as? UILabel).text = postsinput[indexPath.row].name
return cell!
}
I am trying to get data from an url in Swift 3 with Alamofire. There is no data coming through on the cell. I know I am messing something up somewhere but I am fairly new to swift 3 and cant see the issue, the code is below:
JSON Structure.
{
posts:
[
{
id: “000000”,
url: "/content/interview",
date: "2016-11-03 09:01:41",
modified: "2016-11-03 09:03:47",
title: "An interview",
summary:
{
value: "<p>Lorem ipsum is simply dummy text</p> ",
format: "filtered_html"
}
]
}
Swift:
import UIKit
import Alamofire
class TableViewController: UITableViewController {
var titles = [String]()
var mainURL = "https://www.testapi.com"
typealias JSONstandard = [String : AnyObject]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callAlamo(url: mainURL)
}
func callAlamo(url : String){
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
print(readableJSON)
if let post = readableJSON["posts"] as? JSONstandard {
if let posts = post["posts"] {
for i in 0..<posts.count {
let post = posts[i] as! JSONstandard
let title = post["title"] as! String
titles.append(title)
self.tableView.reloadData()
}
}
}
}
catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = titles[indexPath.row]
return cell!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The above bring no data into the "cell". Any help would be appreciated.
First of all a JSON dictionary in Swift 3 is [String:Any]
typealias JSONstandard = [String : Any]
The author of the tutorial should name it JSONdictionary to make it clearer.
The value for posts is an array, JSON collection objects are very easy to identify:
[] is array
{} is dictionary
...
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts { // don't use ugly C-style loops
let title = post["title"] as! String
titles.append(title)
}
self.tableView.reloadData() // reload the table view after the loop
}
...
PS : In Swift (1-3) passing .mutableContainers is pretty useless.
Add UITableViewDataSource methode:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
Do not reloadData()too often:
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
print(readableJSON)
if let post = readableJSON["posts"] as? JSONstandard {
if let posts = post["posts"] {
for i in 0..<posts.count {
let post = posts[i] as! JSONstandard
let title = post["title"] as! String
titles.append(title)
}
self.tableView.reloadData() // moved out of loop
}
}
}
catch {
print(error)
}
}
If the problem persists:
Log: titles.count
You problem is here may be
if let posts = post["posts"] {
---
}
in previous line you get posts by readableJSON["posts"]. Post has no node named "posts".
try this code:
if let allPost = readableJSON["posts"] {
var posts = allPost as! NSArray
for post in posts {
let title = post["title"] as! String
titles.append(title)
self.tableView.reloadData()
}
}