I am new to swift and have set up a table which fills using data from an sql database.
The table loads fine but occasionally it gives the error:
"Fatal Error: Index out of range".
It doesn't happen all the time just every now and again.
Also I have migrated from parse to using sql and http requests. Have I taken the correct approach to this when populating the data into the table?
Any help much appreciated!
#IBOutlet var tableView: UITableView!
var tableData = [String]()
var tableImages = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
if Reachability.isConnectedToNetwork() == true {
self.tableView.hidden = true
self.tableData.removeAll(keepCapacity: true)
self.tableImages.removeAll(keepCapacity: true)
var nib = UINib(nibName: "vwTblCell3", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell3")
let request = NSURLRequest(URL: NSURL(string: "********.php")!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{
(response: NSURLResponse?, data: NSData?, error: NSError?)-> Void in
let str2 = String(data: data!, encoding: NSUTF8StringEncoding)
let str3 = Int(str2!)!
let url = NSURL(string: "********")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)
print(str3)
var i = 0
while i < str3 {
print(jsonResult[i]["title"]! as! String)
print(jsonResult[i]["image"]! as! String)
self.tableData.append(jsonResult[i]["title"]! as! String)
self.tableImages.append(jsonResult[i]["image"]! as! String)
i = i + 1
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}
} catch {
print("JSON serialization failed")
}
}
}
task.resume()
});
print(tableData)
self.tableView.hidden = false
}
}
// 2
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.count
}
// 3
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: TblCell3 = self.tableView.dequeueReusableCellWithIdentifier("cell3") as! TblCell3
cell.lblAffiliate.text = tableData[indexPath.row]
let url3 = NSURL(string: "https://www.********.co.uk/\(tableImages[(indexPath as NSIndexPath).row]).png")
cell.affiliateImage.sd_setImageWithURL(url3)
return cell
}
// 4
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Row \(indexPath.row) selected")
}
// 5
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 400
}
}
I hope this helps. I changed a couple small things around for better code (half could be considered bias). I think the issue is mostly that you were reloading the tableView in the loop. Everything else was just a slightly better way to handle this case. I put everything in viewDidLoad, and made the tableView load empty input prequel to receiving data. I think this is more standard for handling this scenario. If you need any other help let me know.
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
var tableData: [String] = []
var tableImages: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
if Reachability.isConnectedToNetwork() == true {
var nib = UINib(nibName: "vwTblCell3", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell3")
let request = NSURLRequest(URL: NSURL(string: "********.php")!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{
(response: NSURLResponse?, data: NSData?, error: NSError?)-> Void in
let str2 = String(data: data!, encoding: NSUTF8StringEncoding)
let str3 = Int(str2!)!
let url = NSURL(string: "********")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)
self.tableData = []
self.tableImages = []
for i in 0..<str3 {
self.tableData.append(jsonResult[i]["title"]! as! String)
self.tableImages.append(jsonResult[i]["image"]! as! String)
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
} catch {
print("JSON serialization failed")
}
}
}
task.resume()
});
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: TblCell3 = self.tableView.dequeueReusableCellWithIdentifier("cell3") as! TblCell3
cell.lblAffiliate.text = tableData[indexPath.row]
let url3 = NSURL(string: "https://www.********.co.uk/\(tableImages[(indexPath as NSIndexPath).row]).png")
cell.affiliateImage.sd_setImageWithURL(url3)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Row \(indexPath.row) selected")
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 400
}
}
The problem is that your call to reloadData() is inside the while loop in which you are building tableData and tableImages. Move that after the while loop, by which point both of those arrays will be fully populated.
Related
I've a collectionview inside my resizable tablviewCells. Tableview has one cell in each 'n' number of sections. Datasource and delegate of collectionview are set to the tableviewCell. There is an API called on tablview's cellForRowAt, and the result is rendered on the collectionview for each cell. After the result is fetched, a delegate tells the tableview that collectionview is loaded and it should reload that cell without calling the API this time. But the problem is that my collectionview data is repeated after every 2 tableviewCells.
I know prepareForReuse should be override to get rid of cell reuse problems. I've implemented prepareForReuse in my collectionviewCells and set my label.text and imageView.image to nil. However i'm not sure what to add to prepareForReuse for my tableviewCell.
// TableView class
override func viewDidLoad() {
super.viewDidLoad()
storiesSections = [....]
tableView.register(UINib(nibName: "RWFeedTableViewCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
tableView.estimatedRowHeight = 1
tableView.rowHeight = UITableView.automaticDimension
}
override func numberOfSections(in tableView: UITableView) -> Int {
return storiesSections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! RWFeedTableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "reuseIdentifier") as! RWFeedTableViewCell
}
cell.delegate = self
cell.fetchData(feedSection: storiesSections[indexPath.section], indexPath: indexPath)
return cell
}
// delegate for tableview reload
func collectionViewDidEnd(updatedFeedSection: FeedSection, indexPath: IndexPath) {
storiesSections[indexPath.section] = updatedFeedSection
tableView.beginUpdates()
tableView.endUpdates()
}
// TableViewCell class
override func awakeFromNib() {
super.awakeFromNib()
initializeCode()
}
func initializeCode() {
// Set layout
self.collectionView.collectionViewLayout = RWWaterfallLayout2()
self.collectionView.register(UINib(nibName: "\(ImageThenTitleViewCell.self)", bundle: nil), forCellWithReuseIdentifier: kImageThenTitleCellID)
self.collectionView.register(UINib(nibName: "\(LeftImageCell.self)", bundle: nil), forCellWithReuseIdentifier: kLeftImageCellID)
self.collectionView.contentInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
self.collectionView.isScrollEnabled = false
self.collectionView.dataSource = self
self.collectionView.delegate = self
}
func fetchData(feedSection: FeedSection, indexPath: IndexPath) {
if feedSection.isLoadComplete {
return
}
if let catID = feedSection.categoryID {
let urlString = URL(string: <urlString>)
let urlRequest = URLRequest(url: urlString!)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error == nil {
} else {
print(error?.localizedDescription as Any)
}
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
guard let todo = try JSONSerialization.jsonObject(with: responseData, options: [])as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
print("success convert data to JSON")
DispatchQueue.main.async {
var updatedFeedSection = feedSection
updatedFeedSection.storiesArray? = (todo["data"]! as! Array)
updatedFeedSection.isLoadComplete = true
self.feedSection = updatedFeedSection
self.collectionView.reloadData()
self.collectionView.performBatchUpdates({
}, completion: { (complete) in
self.collectionViewHeightConstraint.constant = self.collectionView.collectionViewLayout.collectionViewContentSize.height + self.collectionView.contentInset.top + self.collectionView.contentInset.bottom
self.delegate?.collectionViewDidEnd(updatedFeedSection: updatedFeedSection, indexPath: indexPath)
})
}
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if self.feedSection == nil {
return 0
} else {
return (self.feedSection?.storiesArray?.count)!
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let indexForTen = indexPath.item%10
let story = self.feedSection?.storiesArray?[indexPath.item]
if indexForTen == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kImageThenTitleCellID, for: indexPath) as! ImageThenTitleViewCell
cell.setupData(story: story!)
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kLeftImageCellID, for: indexPath) as! LeftImageCell
cell.setupData(story: story!)
return cell
}
}
override func prepareForReuse() {
super.prepareForReuse()
}
// Collectionview Cell
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func setupData(story: Dictionary<String, Any>){
self.storyImage.image = nil // reset the image
let thumbImage = story["image"] as! Dictionary<String, String>
self.storyTitle.text = story["t"] as? String
self.storyImage.downloaded(from: (thumbImage["m"])!)
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.borderWidth = 1
self.layer.cornerRadius = 8
}
override func prepareForReuse() {
super.prepareForReuse()
storyImage.image = nil
storyTitle.text = nil
}
// FeedSection struct
struct FeedSection {
var categoryID: String?
var storiesArray : [Dictionary<String, Any>]?
var isLoadComplete: Bool
init(categoryID: String) {
self.categoryID = categoryID
self.storiesArray = []
self.isLoadComplete = false
}
}
Currently the 3rd tableviewCell repeats the data of 1st tablviewCell. How to avoid repeating cell data?
Only problem was the feedSection object in TableViewCell. It should be initialized at the time fetchData() is called. And just reload the collectionView if isLoadComplete is true.
Also since isLoadComplete is set on completion handler of URLSession, I set it to true the time API is called. So the same api will not be called while waiting for response. Maybe an enum could be set for api call and api response events on FeedSection. But for now this works.
func fetchData(feedSection: FeedSection, indexPath: IndexPath) {
self.feedSection = feedSection
if self.feedSection.isLoadComplete {
self.collectionView.reloadData()
return
}
if let catID = feedSection.categoryID {
let urlString = URL(string: <urlString>)
let urlRequest = URLRequest(url: urlString!)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
self.feedSection.isLoadComplete = true
self.delegate?.collectionViewDidEnd(updatedFeedSection: self.feedSection, indexPath: indexPath)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error == nil {
} else {
print(error?.localizedDescription as Any)
}
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
guard let todo = try JSONSerialization.jsonObject(with: responseData, options: [])as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
print("success convert data to JSON")
DispatchQueue.main.async {
self.feedSection.storiesArray? = (todo["data"]! as! Array)
self.feedSection.isLoadComplete = true
self.collectionView.reloadData()
self.collectionView.performBatchUpdates({
}, completion: { (complete) in
self.collectionViewHeightConstraint.constant = self.collectionView.collectionViewLayout.collectionViewContentSize.height + self.collectionView.contentInset.top + self.collectionView.contentInset.bottom
self.delegate?.collectionViewDidEnd(updatedFeedSection: self.feedSection, indexPath: indexPath)
})
}
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
}
}
Set UITableView.reloadData() after get the data.
And check if you set CollectionView.reloadData(), if yes then remove reloadData() of UICollectionView. Only set UITableView.reloadData()
I have a tableview.
Each cell opens a new ViewController and loads a .txt file to a textview from my github repo.
But now i want to make each cells to load a different .txt file from the same repo.
So like the first cell loads the first.txt, the second loads the second.txt and so on
is this even possible?
It would be like a news reader app where you click on a title and can read the article.
Here is my current code which is bad but im a beginner :(
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global().async {
let content = self.downloadContent()
DispatchQueue.main.async {
self.myTextView.text = content
}
}
}
func downloadContent() -> String {
var data : Data!
data = try? Data(contentsOf: URL(string: "https://raw.githubusercontent.com/SiposPtr/umszkiapp/master/cikk2.txt")!)
let data_str = String(data: data, encoding: .utf8)
return data_str!
}
I upload my files to a new github repo so you can see the whole stuff:
https://github.com/SiposPtr/stackoverflow
Could you please check if this is working?
import UIKit
class TableViewController: UITableViewController {
var TableData: Array<String> = Array<String>()
var currentCell: String?
var selectedValue: String?
var numberOfFileToLoad: Int = 1
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("https://raw.githubusercontent.com/SiposPtr/umszkiapp/master/cimek.json")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
cell.textLabel!.numberOfLines = 2;
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90.0;
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedValue = TableData[indexPath.row]
numberOfFileToLoad = indexPath.row + 1
}
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 hir_lista = json as? NSArray {
for i in 0 ..< data_list.count
{
if let hir_obj = hir_lista[i] as? NSDictionary
{
if let cim_nev = hir_obj["cim"] as? String
{
if let hir_code = hir_obj["datum"] as? String
{
TableData.append(cim_nev + "\n(" + hir_code + ")")
}
}
}
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
// ez működik, de a run utáni első cikknek üres a titléje és akk csúszik minden cím eggyel
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "gotoSentences"{
let nextViewController = segue.destination as! HirNezetViewController
nextViewController.title = selectedValue
print(selectedValue)
nextViewController.numberOfFileToLoad = numberOfFileToLoad
print(numberOfFileToLoad)
}
}
#IBAction func reloadButton(_ sender: Any) {
let alert = UIAlertController(title: "A cikkeket újratöltöttem", message: "Kattints a gombra az eltüntetéshez", preferredStyle: .alert)
let ok = UIAlertAction(title: "Rendben", style: .default, handler: { action in
})
alert.addAction(ok)
get_data_from_url("https://raw.githubusercontent.com/SiposPtr/umszkiapp/master/cimek.json")
tableView.reloadData()
}
}
import UIKit
class HirNezetViewController: UIViewController {
var data:String!
var content: String?
var numberOfFileToLoad: Int = 1
#IBOutlet weak var myTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global().async {
let content = self.downloadContent()
DispatchQueue.main.async {
self.myTextView.text = content
}
}
}
func downloadContent() -> String {
var data : Data!
data = try? Data(contentsOf: URL(string: "https://raw.githubusercontent.com/SiposPtr/umszkiapp/master/cikk\(String(numberOfFileToLoad)).txt")!)
let data_str = String(data: data, encoding: .utf8)
return data_str!
}
}
I use swiftyJson to parse data and, but do not know how to parse array.
Here is code.
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var json:JSON = JSON.null
var urlSession = URLSession(configuration: .default)
#IBOutlet weak var myTableView: UITableView!
var pokamon = [[String:AnyObject]]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pokamon.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
var dict = pokamon[indexPath.row]
cell.nameLbl.text = dict["name"] as? String
cell.typesLbl.text = dict["types"]?[0] as? String
cell.hpLbl.text = dict["hp"] as? String
cell.subtypeLbl.text = dict["subtype"] as? String
if let image = URL(string: dict["imageUrl"] as! String){
let task = urlSession.downloadTask(with: image) { (url, repsponse, error) in
if error != nil{
print("sorry")
return
}
if let okURL = url{
do{
let downloadImage = UIImage(data: try Data(contentsOf: okURL))
DispatchQueue.main.async {
cell.myImage.image = downloadImage
}
}catch{
print("error")
}
}
}
task.resume()
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 224
}
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
Alamofire.request("https://api.pokemontcg.io/v1/cards").responseJSON(completionHandler: { response in
if response.result.isSuccess {
let json:JSON = try! JSON(data: response.data!)
let swiftyJsonVar = JSON(response.result.value!)
if let resData = swiftyJsonVar["cards"].arrayObject{
self.pokamon = resData as! [[String:AnyObject]]
}
if self.pokamon.count > 0{
self.myTableView.reloadData()
}
} else {
print("error: \(response.error)")
}
})
}
}
From cellForRowAt in tableView, it shows "Ambiguous use of 'subscript'" with below code, have no idea how to solve it. The rest like "name", "hp", and "subtype" are no problem!
cell.typesLbl.text = dict["types"]?[0] as? String
Could anyone help me with this error?
Thanks!
The compiler must know the type of any subscripted object. Tell the compiler that you expect an array of strings.
cell.typesLbl.text = (dict["types"] as? [String])?.first
In Swift 3+ all JSON values are Any not AnyObject so declare the array
var pokamon = [[String:Any]]()
I am currently trying to display firebase objects in my tableview. However, I am only getting empty prototype cells. Thanks if you can take a glance at it!
import UIKit
import Firebase
class UsersTableViewController: UITableViewController {
var user = [User]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getusers() {
let userID = Auth.auth().currentUser?.uid
let rootRef = Database.database().reference()
let query = rootRef.child("users").queryOrdered(byChild: "fullname")
query.observe(.value) { (snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
if let value = child.value as? NSDictionary {
let userToShow = User()
let fullname = value["fullname"] as? String ?? "Name not found"
let uid = value["uid"] as? String ?? "uid not found"
userToShow.fullname = fullname
userToShow.userID = uid
self.user.append(userToShow)
DispatchQueue.main.async { self.tableView.reloadData() }
}
}
}
}
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 user.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! TableViewCell
cell.nameLabel.text = self.user[indexPath.row].fullname
cell.userID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
return cell
}
}
extension UIImageView {
#objc func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}}
Thanks again for anyone willing to help! I am currently using Swift 4 with Google's Firebase API.
p.s. I know that I have connected delegate and dataSource. I am also sure that I have properly titled my Identifier. Thanks!
class ProductTableViewController: UITableViewController
{
var products = [Product]()
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return products.count // zero
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath) as! ProductCell
cell.userIdLabel?.text = "user id" + "$\(products[indexPath.row].userId)"
cell.idLabel?.text = "id" + "$\(products[indexPath.row].id)"
cell.titleLabel?.text = products[indexPath.row].title
cell.bodyLabel?.text = products[indexPath.row].body
return cell
}
func getData(){
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [[String:Any]]
for post in json{
let product = Product()
product.userId = post["userId"] as! Int
product.id = post["id"] as! Int
product.title = post["title"] as! String
product.body = post["body"] as! String
self.products.append(product)
}
//OperationQueue.main.addOperation({ () -> Void in self.tableView.reloadData()})
} catch let error as NSError {
print(error)
}
//HERE!!!
OperationQueue.main.addOperation({ () -> Void in self.tableView.reloadData()})
}).resume()
}
}
When my UITableViewController executed first of all will implement func tableView and he will return zero count cause getData() didn't run yet and of course second tableView who returning my Cell will not implement.
And now, I wanna see what parsed my getData() in order to do I try to reload my tableView with OperationQueue.main.addOperation({ () -> Void in self.tableView.reloadData()})but caught an error :
Thread1 :SIGABRT.
How I should correctly reload my tableView?
Try this
func getData(){
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [[String:Any]]
for post in json{
let product = Product()
product.userId = post["userId"] as! Int
product.id = post["id"] as! Int
product.title = post["title"] as! String
product.body = post["body"] as! String
self.products.append(product)
}
// just reload here after finish appends
self.tableView.reloadData()
} catch let error as NSError {
print(error)
}
}).resume()
}