How do automatically stop activity indicator after the refresh button is pressed and loading of content is done in UITableview JSON
I already have to the code to start the spinning and the button
Here is full code
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var json_data_url = "http://www.howtotechworld.com/json_table_view_images%20(1).json"
var image_base_url = ""
var isProgressShowing = true;
var TableData:Array< datastruct > = Array < datastruct >()
enum ErrorHandler:ErrorType
{
case ErrorFetchingResults
}
struct datastruct
{
var imageurl:String?
var description:String?
var image:UIImage? = nil
init(add: NSDictionary)
{
imageurl = add["url"] as? String
description = add["description"] as? String
}
}
#IBOutlet var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableview.dataSource = self
tableview.delegate = self
get_data_from_url(json_data_url)
}
override func viewWillAppear(animated: Bool) {
let barButtonItem = UIBarButtonItem(title: "Refresh", style: .Plain, target: self, action: "refreshTapped");
self.navigationItem.rightBarButtonItem = barButtonItem;
}
func refreshTapped() {
addProgressIndicator(isProgressShowing);
get_data_from_url(json_data_url)
}
func addProgressIndicator(show : Bool) {
isProgressShowing = !show;
if(show) {
let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle:UIActivityIndicatorViewStyle.Gray)
myActivityIndicator.startAnimating()
let barButtonItem = UIBarButtonItem(customView: myActivityIndicator)
self.navigationItem.rightBarButtonItem = barButtonItem
} else {
self.navigationItem.rightBarButtonItem = nil;
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let data = TableData[indexPath.row]
cell.textLabel?.text = data.description
if (data.image == nil)
{
cell.imageView?.image = UIImage(named:"image.jpg")
load_image(image_base_url + data.imageurl!, imageview: cell.imageView!, index: indexPath.row)
}
else
{
cell.imageView?.image = TableData[indexPath.row].image
}
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return TableData.count
}
func get_data_from_url(url:String)
{
let url:NSURL = NSURL(string: url)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
dispatch_async(dispatch_get_main_queue(), {
self.extract_json(data!)
return
})
}
task.resume()
}
func extract_json(jsonData:NSData)
{
let json: AnyObject?
do {
json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
} catch {
json = nil
return
}
if let list = json as? NSArray
{
for (var i = 0; i < list.count ; i++ )
{
if let data_block = list[i] as? NSDictionary
{
TableData.append(datastruct(add: data_block))
}
}
do
{
try read()
}
catch
{
}
do_table_refresh()
}
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableview.reloadData()
return
})
}
func load_image(urlString:String, imageview:UIImageView, index:NSInteger)
{
let url:NSURL = NSURL(string: urlString)!
let session = NSURLSession.sharedSession()
let task = session.downloadTaskWithURL(url) {
(
let location, let response, let error) in
guard let _:NSURL = location, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let imageData = NSData(contentsOfURL: location!)
dispatch_async(dispatch_get_main_queue(), {
self.TableData[index].image = UIImage(data: imageData!)
self.save(index,image: self.TableData[index].image!)
imageview.image = self.TableData[index].image
return
})
}
task.resume()
}
func read() throws
{
do
{
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let fetchRequest = NSFetchRequest(entityName: "Images")
let fetchedResults = try managedContext.executeFetchRequest(fetchRequest)
for (var i=0; i < fetchedResults.count; i++)
{
let single_result = fetchedResults[i]
let index = single_result.valueForKey("index") as! NSInteger
let img: NSData? = single_result.valueForKey("image") as? NSData
TableData[index].image = UIImage(data: img!)
}
}
catch
{
print("error")
throw ErrorHandler.ErrorFetchingResults
}
}
func save(id:Int,image:UIImage)
{
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Images",
inManagedObjectContext: managedContext)
let options = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
let newImageData = UIImageJPEGRepresentation(image,1)
options.setValue(id, forKey: "index")
options.setValue(newImageData, forKey: "image")
do {
try managedContext.save()
} catch
{
print("error")
}
}
}
You will need to keep a reference to myActivityIndicator and stop it in do_table_refresh() as shown below.
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableview.reloadData()
myActivityIndicator.stopAnimating()
return
})
}
Edit: Just had a quick thought after looking at your code in the question.
If you would like to hide myActivitIndicator using addProgressIndicator(isProgressShowing) , you will have to make sure that isProgressShowing is set to FALSE, then in the code that I have given above, replace myActivityIndicator.stopAnimating() with addProgressIndicator(isProgressShowing).
You will also need to update the addProgressIndicator function and add myActivityIndicator.stopAnimating() to the else condition.
If I understand your question right then I think below is what you want.
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([indexPath row] == ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row){
//end of loading
//for example [activityIndicator stopAnimating];
}
}
and for swift it is like this
func cellForRowAtIndexPath(_ indexPath: NSIndexPath) -> UITableViewCell?{
if(indexPath.row = tableView.indexPathsForVisibleRows().lastObject().row{
//end of loading
//for example [activityIndicator stopAnimating];
}
return yourCell;
}
I don't know swift much, but i guess you will have got the idea how to do it.
Add this code after do_table_refresh(): addProgressIndicator(!isProgressShowing);
Related
I don't understand why my application works well on the Simulator but instead when I run on iPhone crashes. What can be?
import UIKit
import CoreData
class HomeTableViewController: UITableViewController{
var arrayEntity : [Questions] = []
override func viewDidLoad(){
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
if (CoreDataController.shared.checkIfIsEmpty() == true) { getJSON() }
else { arrayEntity = CoreDataController.shared.loadQuestion()!
//reload della tableview quando l'array si modifica
self.tableView.reloadData()
}
}
struct ProvaREST{
var userId: Int = 0
var id: Int = 0
var title: String = ""
var body: String = ""
static func parsereviewJSONData(data: Data) -> [ProvaREST] {
var provaREST = [ProvaREST]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
// Parse JSON data
if let reviews = jsonResult as? [Dictionary<String, Any>] {
for review in reviews {
var newReview = ProvaREST()
newReview.userId = review["userId"] as! Int
newReview.id = review["id"] as! Int
newReview.title = review["title"] as! String
newReview.body = review["body"] as! String
provaREST.append(newReview)
}
}
} catch let err {
print(err)
}
return provaREST
}
}
func getJSON(){
var reviews = [ProvaREST]()
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
guard let URL = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return }
var request = URLRequest(url: URL)
request.httpMethod = "GET"
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
if (error == nil) {
// Parse JSON Data
if let data = data {
reviews = ProvaREST.parsereviewJSONData(data: data)
//Core data saving
for i in 0 ..< reviews.count{
CoreDataController.shared.addQuestion(userID: reviews[i].userId, id: reviews[i].id, title: reviews[i].title, body: reviews[i].body)
}
//quando finisco di aggiungere, tengo in memoria (per zone fuori copertura) ed estraggo i dati per la tableview
self.arrayEntity = CoreDataController.shared.loadQuestion()!
self.tableView.reloadData()
}
} else {
// Failure connection
print("Nessuna connessione")
}
})
task.resume()
session.finishTasksAndInvalidate()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayEntity.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = arrayEntity[indexPath.row].body
cell.detailTextLabel?.text = String(arrayEntity[indexPath.row].id)
return cell
}
}
and
import Foundation
import UIKit
import CoreData
class CoreDataController {
static let shared = CoreDataController()
private var context: NSManagedObjectContext
private init() {
let application = UIApplication.shared.delegate as! AppDelegate
self.context = application.persistentContainer.viewContext
}
func addQuestion(userID: Int, id: Int, title: String, body: String) {
let entity = NSEntityDescription.entity(forEntityName: "Questions", in: self.context)
let newQuestion = Questions(entity: entity!, insertInto: self.context)
newQuestion.userid = Int32(userID)
newQuestion.id = Int32(id)
newQuestion.title = title
newQuestion.body = body
do {
try self.context.save()
} catch{
print("Errore")
}
}
func loadQuestion() -> [Questions]? {
print("Recupero libri:")
let fetchRequest: NSFetchRequest<Questions> = Questions.fetchRequest()
do {
let array = try self.context.fetch(fetchRequest) as [Questions]
guard array.count > 0 else {print("[EHY!] Non ci sono elementi da leggere "); return array}
return array
}catch let err{
print(err)
return nil
}
}
func checkIfIsEmpty() -> Bool{
let fetchRequest: NSFetchRequest<Questions> = Questions.fetchRequest()
do {
let array = try self.context.fetch(fetchRequest)
guard array.count > 0 else { return true }
return false
}catch{
print("Errore nella fetchRequest")
return false
}
}
}
The coredatacontroller class is the class that handles database operationsThe coredatacontroller class is the class that handles database operationsThe coredatacontroller class is the class that handles database operations
I am getting build errors when trying to display jSON data in Xcode using Swift 3. I am going to copy a portion of my code to this page with hopes you guys can assist me.
I have found similar questions on this site however answers don't seem to help.
class FilmsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
weak var tableView : UITableView!
var FilmArray = [String]()
let film_url = "https://www.testing.com/api/resources/films/1"
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath) as! FilmsAPITableViewCell
// Adding the right informations
cell.movieTitle.text = FilmArray[indexPath.row]
// Returning the cell
return cell
}
// #IBOutlet weak var FilmsView: UITableView!
// weak var tableView : UITableView!
// var FilmArray = [String]()
//
// let film_url = "https://www.distribber.com/api/resources/films/1"
//
override func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView (frame:view.bounds)
view.addSubview(tableView)
self.tableView = tableView
tableView.dataSource = self
tableView.delegate = self
// func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return 1
// }
// func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// // Getting the right element
// //let films = FilmArray[indexPath.row]
//
//
// // Instantiate a cell
// //let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "moviecell")
// let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! FilmsAPITableViewCell
// // cell.movieTitle.text = FilmArray[indexPath.row]
// // Adding the right informations
// cell.movieTitle.text = FilmArray[indexPath.row]
// // Returning the cell
// return cell
// }
// }
//}
let url:URL = URL(string: film_url)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.setValue("740c94c51891c02b64d6c78840b478fe0b02fe2c", forHTTPHeaderField: "X-API-KEY")
request.setValue("Basic YmhlZW0uZW5nckBnbWFpbC5jb206YmgzM20=", forHTTPHeaderField: "Authorization")
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = ""
// for (key, value) in post_data
// {
// paramString = paramString + (key as! String) + "=" + (value as! String) + "&"
// }
//
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data!, options: [])
// Prasing JSON
var parsedData = try JSONSerialization.jsonObject(with: data!, options: []) as! [String:Any]
print(parsedData)
if let FilmArray = parsedData["films"] as? NSArray {
for movieTitle in FilmArray{
if let filmDict = movieTitle as? NSDictionary{
if let film = filmDict.value(forKey: "title") {
self.FilmArray.append(film as! String)
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}
}
print("Hello")
self.tableView.reloadData()
print(self.FilmArray)
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
if let data_block = server_response["data"] as? NSDictionary
{
if let session_data = data_block["session"] as? String
{
// self.login_session = session_data
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "session")
// DispatchQueue.main.async(execute: self.LoginDone)
}
}
})
task.resume()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is also output from FilmsAPITableViewCell.swift
import UIKit
import UIKit
class FilmsAPITableViewCell: UITableViewCell {
#IBOutlet weak var movieTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
The reason why movieTitle is nil is because your custom cell class does not have that label outlet. You need to create a UILabel in your .xib (or storyboard) and create an outlet connection inside your custom cell class.
It also seems like no self.tableView.reloadData() exists in your completion block. Try adding that right after the print("Hello") line.
P.S. Don't forget to dispatch the reload to the main queue.
Here is also your code which I edited as to get it working:
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
let url:URL = URL(string: film_url)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.setValue("740c94c51891c02b64d6c78840b478fe0b02fe2c", forHTTPHeaderField: "X-API-KEY")
request.setValue("Basic YmhlZW0uZW5nckBnbWFpbC5jb206YmgzM20=", forHTTPHeaderField: "Authorization")
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = ""
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
var json:Any?
do
{
if let existingData = data {
json = try JSONSerialization.jsonObject(with: existingData, options: [])
}
// Prasing JSON
if let parsedData = json as? [[String:Any]] {
for dict in parsedData {
if let title = dict["title"] as? String {
self.FilmArray.append(title)
}
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
if let data_block = server_response["data"] as? NSDictionary
{
if let session_data = data_block["session"] as? String
{
// self.login_session = session_data
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "session")
// DispatchQueue.main.async(execute: self.LoginDone)
}
}
})
task.resume()
}
I try to update my tableview after my REST-call is finished and all entities are stored in CoreData. I tried dispatch_asynch but the tableview doesn't reload when expected. I am using a UIRefreshControl to trigger refreshing. Usually, the correct tableview data is displayed after 2 refreshes. I have no idea why.
I can confirm that my tableview instance IS NOT nil.
#IBAction func refreshTriggered(sender: UIRefreshControl) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.evMan.retrieveAndSaveEvents(self.pubMan.getAllPublishers())
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
}
This is my retrieveAndSaveEvents method from my 'EventManager' evMan:
func retrieveAndSaveEvents(forPublishers: [PUBLISHERS]) {
for publisher in forPublishers {
let pubId = publisher.id as Int
let str = "/publishers/\(pubId)/events"
// resty is an instance of my REST-api wrapper
self.resty.GET(self.server, route: str, onCompletion: {json in
let result = json.asArray
for var i = 0; i < result!.count; i++ {
if !self.isIDAlreadyInDB(json[i]["id"].asInt!) {
let newEv = NSEntityDescription.insertNewObjectForEntityForName("EVENTS", inManagedObjectContext: self.context!) as! EVENTS
newEv.headline = json[i]["headline"].asString!
newEv.id = json[i]["id"].asInt!
newEv.content = json[i]["content"].asString!
newEv.ofPublisher = publisher
do {
try self.context!.save()
} catch _ {
}
print("New Event from \(publisher.name): \(newEv.headline)")
}
}
})
}
}
FYI, here's my cellForRowAtIndexPath: (I am using a Custom UITableViewCell)
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("eventCell") as? EventCell
let curEv = evMan.getEvents()[indexPath.row]
cell?.infoLabel.text = curEv.ofPublisher?.name
cell?.myImageView.image = UIImage(named: "icon.png")
cell?.detailLabel.text = curEv.headline
cell?.timeLabel.attributedText = NSAttributedString(string: self.dateFormatter.stringFromDate(curEv.updatedAt))
cell?.contentView.backgroundColor = UIColor.clearColor()
cell?.backgroundColor = UIColor(white: 1.0, alpha: 0.5)
return cell!
}
Here is my REST-wrapper:
class REST: NSObject {
// Basic Auth
let sConfig = ServerConfig()
var username = "rest"
var password = "resttest"
override init() {
username = sConfig.getUserLogin().user
password = sConfig.getUserLogin().pass
}
func GET(server: String, route: String, onCompletion: (JSON) -> Void) {
let route = server+route
makeHTTPGetRequest(route, onCompletion: { json, err in
onCompletion(json as JSON)
})
}
func makeHTTPGetRequest(path: String, onCompletion: ServiceResponse) {
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let loginString = NSString(format: "%#:%#", username, password)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
let loginvalue = "Basic " + base64LoginString
// add Headers
request.addValue(loginvalue, forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data!)
onCompletion(json, error)
})
task.resume()
}
}
#IBAction func refreshTriggered(sender: UIRefreshControl) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.evMan.retrieveAndSaveEvents(self.pubMan.getAllPublishers())
})
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
Now, you cannot guarantee reloadData() happens after self.evMan.retrieveAndSaveEvents(self.pubMan.getAllPublishers()) , because they are not happen in the same queue. And probably, reloadData() happens before retrieve.
Option 1:
You should put the block :
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
at the end of func retrieveAndSaveEvents(self.pubMan.getAllPublishers())
Option 2 :
#IBAction func refreshTriggered(sender: UIRefreshControl) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.evMan.retrieveAndSaveEvents(self.pubMan.getAllPublishers())
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
})
}
EDIT:
I did not see there is another queue in retrieveAndSaveEvents
So, put the
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
at the end of:
self.resty.GET(self.server, route: str, onCompletion: {json in
let result = json.asArray
for var i = 0; i < result!.count; i++ {
if !self.isIDAlreadyInDB(json[i]["id"].asInt!) {
let newEv = NSEntityDescription.insertNewObjectForEntityForName("EVENTS", inManagedObjectContext: self.context!) as! EVENTS
newEv.headline = json[i]["headline"].asString!
newEv.id = json[i]["id"].asInt!
newEv.content = json[i]["content"].asString!
newEv.ofPublisher = publisher
do {
try self.context!.save()
} catch _ {
}
print("New Event from \(publisher.name): \(newEv.headline)")
}
}
})
The view I'm developing does the following:
Sends a GET request to the API to retrieve a list of users
Sends GET requests to the API to retrieve profile images from the list of users
Display the images in TableViewCells
However, I'm having problem managing the tasks and the queues. What is the best way to be sure that all the requests and tasks are done before populating the Table View?
Here's the code:
import UIKit
class homeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var jsonData : [NSDictionary] = [NSDictionary]()
var imageUrls: NSDictionary = NSDictionary()
var urlsArray: [NSURL] = [NSURL]()
override func viewDidLoad() {
super.viewDidLoad()
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
self.refreshData()
self.getImage()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
})
}
override func viewWillAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return jsonData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var type = jsonData[indexPath.row]["type"] as! Int
for typej in jsonData {
let t : Int = typej["type"] as! Int
println("type : \(t)")
}
if type == 1 {
let cell1 : cellTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! cellTableViewCell
/* //If images url are retrieved, load them. Otherwise, load the placeholders
if self.urlsArray.isEmpty == false {
println("Tiè: \(self.urlsArray[indexPath.row])")
if let data = NSData(contentsOfURL: self.urlsArray[indexPath.row]) {
cell1.profileImg?.image = UIImage(data: data)
}
} else {
cell1.profileImg?.image = UIImage(named: "placeholder.png")
}*/
let block: SDWebImageCompletionBlock! = {
(image: UIImage!, error: NSError!, cacheType: SDImageCacheType, imageURL: NSURL!) -> Void in
println(self)
}
println("url Array: \(self.urlsArray)")
let url = NSURL(string: "http://adall.ga/s/profile-1439584252497.png")
if UIApplication.sharedApplication().canOpenURL(urlsArray[indexPath.row]) {
cell1.profileImg.sd_setImageWithURL(urlsArray[indexPath.row], completed: block)
} else {
cell1.profileImg.sd_setImageWithURL(url, completed: block)
}
cell1.testLbl.text = (self.jsonData[indexPath.row]["author"] as? String)!
return cell1
} else {
let cell2 : cell2TableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell2") as! cell2TableViewCell
return cell2
}
}
func refreshData() {
let requestURL = NSURL(string:"http://adall.ga/api/feeds/author/mat/0")!
var request = NSMutableURLRequest(URL: requestURL)
request.HTTPMethod = "GET"
request.addValue(userToken, forHTTPHeaderField: "tb-token")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
data, response, error in
println(response)
var dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
println(dataString)
//let jsonResult : NSDictionary = (NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary)!
//jsonData = (NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers , error: nil) as? NSArray)!
self.jsonData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: nil) as! [NSDictionary]
}
task.resume()
var index: Int
for index = 0; index < 10000; ++index {
print("Index: \(index), Task state: \(task.state)")
}
}
func getImage() {
var i = 0
for jsonSingleData in jsonData {
let author = jsonSingleData["author"] as! String
let requestURL2 = NSURL(string: "http://adall.ga/api/users/" + author + "/image")!
var request2 = NSMutableURLRequest(URL: requestURL2)
request2.HTTPMethod = "GET"
request2.addValue(userToken!, forHTTPHeaderField: "tb-token")
let session2 = NSURLSession.sharedSession()
let task2 = session2.dataTaskWithRequest(request2) {
data, response, error in
println("response= \(response)")
var dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
println(dataString)
self.imageUrls = (NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary)
if self.imageUrls["url"] != nil {
//check if exists
let imageUrl = self.imageUrls["url"] as! String
let url = NSURL(string: "http://" + imageUrl)
self.urlsArray.append(url!)
} else {
let imageUrl = "http://shackmanlab.org/wp-content/uploads/2013/07/person-placeholder.jpg"
let url = NSURL(string: imageUrl)
self.urlsArray.append(url!)
}
}
task2.resume()
self.tableView.reloadData()
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
The point of the issue is the following code:
dispatch_async(backgroundQueue, {
self.refreshData()
self.getImage()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
})
The NSURLSession working in the background thread, so your jsonData is empty when the self.getImage() and reloadData are executed.
You can call the self.getImage() after this line
self.jsonData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: nil) as! [NSDictionary]
in the session.dataTaskWithRequest completed block and calls reloadData(on the dispatch_get_main_queue) in the completed block of the session2.dataTaskWithRequest.
I think this will solved your issue.
Below is the my code!!!
import UIKit
class myhomefeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableData = []
var imageCache = [String:UIImage]()
var imageCache1 = [String:UIImage]()
var imageCache2 = [String:UIImage]()
#IBOutlet var appsTableView: UITableView!
var refreshControl:UIRefreshControl!
let PageSize = 5
#IBOutlet var tableViewFooter:Reload!
var loading = false
override func viewDidLoad() {
super.viewDidLoad()
self.tableViewFooter.hidden = true
loadmyhomefeeddata(0, size: PageSize)
self.refreshControl = UIRefreshControl()
self.refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
self.refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.appsTableView.addSubview(refreshControl)
}
func refresh(refreshControl: UIRefreshControl) {
loadmyhomefeeddata(0, size: PageSize)
refreshControl.endRefreshing()
}
func loadSegment(offset:Int, size:Int) {
if (!self.loading) {
self.setLoadingState(true)
if currentpage < toPage {
}
else if currentpage > toPage
{
self.setLoadingState(false)
}
}
else
{
println("Not Loading")
}
}
func setLoadingState(loading:Bool) {
self.loading = loading
self.tableViewFooter.hidden = !loading
}
func scrollViewDidScroll(scrollView: UIScrollView) {
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
if (maximumOffset - currentOffset) <= 40 {
loadSegment(currentpage, size: tableData.count)
}
}
// pull to refresh list
#IBAction func writeyouridea(sender: AnyObject) {
let viewController=self.storyboard?.instantiateViewControllerWithIdentifier("writeyouridea") as? UIViewController
self.presentViewController(viewController!, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return tableData.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myhomefeedcell", forIndexPath: indexPath) as! myhomefeedTableViewCell
// Configure the cell...
if let rowData: NSDictionary = self.tableData[indexPath.row] as? NSDictionary,
urlString = rowData["imgfile"] as? String,
imgURL = NSURL(string: urlString),
// imgData = NSData(contentsOfURL: imgURL),
countryString = rowData["cflag"] as? String,
countryimgURL = NSURL(string: countryString),
// countryimgData = NSData(contentsOfURL: countryimgURL),
ideaimageString = rowData["ideapicture"] as? String,
ideaimageURL = NSURL(string: ideaimageString),
// ideaimagedata = NSData(contentsOfURL: ideaimageURL),
userfullname = rowData["name"] as? String,
category = rowData["categoryname"] as? String,
ideadesc = rowData["idea"] as? String,
time = rowData["createddate"] as? String,
ideatitle = rowData["title"] as? String {
cell.ideadesc.text = ideadesc
cell.username.text = userfullname
cell.categoryname.text = category
cell.feedimage.image = UIImage(named: "cross")
cell.userimage.image = UIImage(named: "cross")
cell.country.image = UIImage(named: "cross")
cell.title.text = ideatitle
cell.time.text = time
//country
if let countryimg = imageCache1[countryString] {
cell.country.image = countryimg
}
else {
let request: NSURLRequest = NSURLRequest(URL: countryimgURL)
let mainQueue = NSOperationQueue.mainQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: mainQueue, completionHandler: { (response, data, error) -> Void in
if error == nil {
let imagecountry = UIImage(data: data)
self.imageCache1[countryString] = imagecountry
// Update the cell
dispatch_async(dispatch_get_main_queue(), {
cell.country.image = imagecountry
})
}
else {
println("Error: \(error.localizedDescription)")
}
})
}
//userimage
if let userimg = imageCache2[urlString] {
cell.userimage.image = userimg
}
else {
let request: NSURLRequest = NSURLRequest(URL: imgURL)
let mainQueue = NSOperationQueue.mainQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: mainQueue, completionHandler: { (response, data, error) -> Void in
if error == nil {
let imageuser = UIImage(data: data)
self.imageCache2[urlString] = imageuser
// Update the cell
dispatch_async(dispatch_get_main_queue(), {
cell.userimage.image = imageuser
})
}
else {
println("Error: \(error.localizedDescription)")
}
})
}
if cell.feedimage.image != nil
{
if let img = imageCache[ideaimageString] {
cell.feedimage.image = img
}
else {
let request: NSURLRequest = NSURLRequest(URL: ideaimageURL)
let mainQueue = NSOperationQueue.mainQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: mainQueue, completionHandler: { (response, data, error) -> Void in
if error == nil {
let image = UIImage(data: data)
self.imageCache[ideaimageString] = image
// Update the cell
dispatch_async(dispatch_get_main_queue(), {
cell.feedimage.image = image
})
}
else {
println("Error: \(error.localizedDescription)")
}
})
}
}
}
return cell
}
func loadmyhomefeeddata(offset:Int, size:Int) {
let rowslimit = size
let urlPath = "url address?noofrowslimit=\(rowslimit)"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if(error != nil) {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary {
if(err != nil) {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
// println(jsonResult)
if let results: NSArray = jsonResult["results"] as? NSArray {
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results
self.appsTableView!.reloadData()
})
}
}
})
task.resume()
}
}
Are you trying to have a infinite scroll? If so, you could try the following. First of all, make the task an instance variable of your controller then add the following UIScrollViewDelegate.
override func scrollViewDidScroll(scrollView: UIScrollView) {
// If you are already loading elements, return. This method is called multiple times
if task?.state == .Running { // You could use the isLoading variable instead
return
}
let offSetY = scrollView.contentOffset.y
let triggerY = scrollView.contentSize.height - tableView.frame.size.height
if (offSetY >= triggerY) {
// The offset of elements should be the amount you currently have, and you want to fetch 5 more elements
self.loadmyhomefeeddata(tableData.count, size: 5)
}
}