Swift - Manage tasks to populate UITableView - ios

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.

Related

UITable Won't display. Value type 'FilmsAPITableViewCell' has no member 'movieTitle'

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()
}

Parsing image from iTunes using JSON to tableviewcontroller

I'm trying to parse data from this data source, Titles are parsed correctly and displayed, but the problem occurred when parsing the images, I got an error: “fatal error: unexpectedly found nil while unwrapping an Optional value”
Here is my Code:
ViewModel.swift
import Foundation
class ViewModel {
let urlString = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topsongs/limit=30/json"
var titles = [String]()
var images = [String]()
func fetchTitles(success:() -> ()) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let url = NSURL(string: urlString)
let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in
let parser = JSONParser()
self.titles = parser.titlesFromJSON(data!)
success()
}
task.resume()
}
func fetchImages(success:() -> ()) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let url = NSURL(string: urlString)
let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in
let parser = JSONParser()
self.images = parser.imagesFromJSON(data!)
success()
}
task.resume()
}
func numberOfSections() -> Int {
return 1
}
func numberOfItemsInSection(section: Int) -> Int {
return titles.count
}
func titleForItemAtIndexPath(indexPath: NSIndexPath) -> String {
return titles[indexPath.row]
}
}
and MyTableViewController.swift
import UIKit
class MyTableViewController: UITableViewController {
let viewModel = ViewModel()
var imageCache = [String:UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
self.refresh()
self.refreshControl = UIRefreshControl()
self.refreshControl?.addTarget(self, action: #selector(MyTableViewController.refresh), forControlEvents: .ValueChanged)
}
func refresh() {
viewModel.fetchTitles {
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
viewModel.fetchImages {
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.viewModel.numberOfSections()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.viewModel.numberOfItemsInSection(section)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTableViewCell
cell.songTitle.text = self.viewModel.titleForItemAtIndexPath(indexPath)
let urlString = self.viewModel.titleForItemAtIndexPath(indexPath)
//found nil
let imgURL: NSURL = NSURL(string: urlString)!
let request: NSURLRequest = NSURLRequest(URL: imgURL)
NSURLConnection.sendAsynchronousRequest(
request, queue: NSOperationQueue.mainQueue(),
completionHandler: {(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
if error == nil {
cell.songImage.image = UIImage(data: data!)
}
})
return cell
}
and JSONParser.swift
import Foundation
class JSONParser {
func titlesFromJSON(data: NSData) -> [String] {
var titles = [String]()
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject],
let feed = json["feed"] as? [String: AnyObject],
entries = feed["entry"] as? [[String: AnyObject]] {
for entry in entries {
if let name = entry["im:name"] as? [String: AnyObject],
label = name["label"] as? String {
titles.append(label)
}
}
}
} catch {
print("error parsing JSON: \(error)")
}
return titles
}
func imagesFromJSON(data: NSData) -> [String] {
var images = [String]()
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject],
let feed = json["feed"] as? [String: AnyObject],
entries = feed["entry"] as? [[String: AnyObject]] {
for entry in entries {
if let name = entry["im:image"]![0] as? [String: AnyObject],
label = name["label"] as? String {
images.append(label)
}
}
}
} catch {
print("error parsing JSON: \(error)")
}
return images
}
}
And I have a class MyTableViewCell subclass of UITableViewCell containing a UILabel and a UIImageView.
I can't figure out what's the problem, and why I'm getting this error. Thank you for your time.
I always recommend you to avoid the use of force-unwrapping and adopt a more secure way of code (e.g using optional binding) avoiding runtime errors. So you can change your code to the following code and avoid the runtime error:
for entry in entries {
if let name = entry["im:image"], let value = name[0] as? [String: AnyObject],
label = value["label"] as? String {
images.append(label)
}
}
In the above way you avoid the use of force-unwrapping.
I hope this help you.

I can not get the json data to display in my second UIViewController

I have the following two functions in my first ViewController. They load a UITableView with over 300 rows. I call the loadRemoteData function inside the ViewDidLoad. Everything works fine in the first ViewController.
// MARK: - parseJSON
func parseJSON(data: NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers)
if let rootDictionary = json as? [NSObject: AnyObject], rootResults = rootDictionary["results"] as? [[NSObject: AnyObject]] {
for childResults in rootResults {
if let firstName = childResults["first_name"] as? String,
let lastName = childResults["last_name"] as? String,
let bioguideId = childResults["bioguide_id"] as? String,
let state = childResults["state"] as? String,
let stateName = childResults["state_name"] as? String,
let title = childResults["title"] as? String,
let party = childResults["party"] as? String {
let eachLegislator = Legislator(firstName: firstName, lastName: lastName, bioguideId: bioguideId, state: state, stateName: stateName, title: title, party: party)
legislators.append(eachLegislator)
}
}
}
} catch {
print(error)
}
}
// MARK: - Remote Data configuration
func loadRemoteData() {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let url = "https://somedomain.com/legislators?order=state_name__asc,last_name__asc&fields=first_name,last_name,bioguide_id"
if let url = NSURL(string: url) {
let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
if let error = error {
print("Data Task failed with error: \(error)")
return
}
if let http = response as? NSHTTPURLResponse, data = data {
if http.statusCode == 200 {
dispatch_async(dispatch_get_main_queue()) {
self.parseJSON(data)
self.tableView.reloadData()
}
}
}
})
task.resume()
}
}
In the second ViewController, I want to display more information about the individual listed in the cell that is tapped, for that I use a different URL such as https://somedomain.com/legislators?bioguide_id=\"\(bioguideId)\" which provides me with a lot more detail. (The data being requested from the JSON Dictionary is different)
The code I use in the second ViewController is just like shown above with the only difference being the URL. I can print the url coming from the previous ViewController and it is displayed in the console log but no json data is shown.
I would appreciate any help.
Thanks
Below is the code for my second ViewController:
import UIKit
class DetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var bioguideId: String?
var currentLegislator: Legislator? = nil
var currentLegislatorUrl: String?
let reuseIdentifier = "Cell"
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var tableView: UITableView!
// MARK: - parseJSON
private func parseJSON(data: NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers)
if let rootDictionary = json as? [NSObject: AnyObject],
rootResults = rootDictionary["results"] as? [[NSObject: AnyObject]] {
for childResults in rootResults {
if let firstName = childResults["first_name"] as? String,
let lastName = childResults["last_name"] as? String,
let bioguideId = childResults["bioguide_id"] as? String,
let state = childResults["state"] as? String,
let stateName = childResults["state_name"] as? String,
let title = childResults["title"] as? String,
let party = childResults["party"] as? String {
currentLegislator = Legislator(firstName: firstName, lastName: lastName, bioguideId: bioguideId, state: state, stateName: stateName, title: title, party: party)
}
}
}
} catch {
print(error)
}
}
// MARK: - Remote Data configuration
func loadRemoteData(url: String) {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let url = currentLegislatorUrl
if let url = NSURL(string: url!) {
let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
if let error = error {
print("Data Task failed with error: \(error)")
return
}
print("Success")
if let http = response as? NSHTTPURLResponse, data = data {
if http.statusCode == 200 {
dispatch_async(dispatch_get_main_queue()) {
self.parseJSON(data)
self.tableView.reloadData()
}
}
}
})
task.resume()
}
}
func loadImage(urlString:String) {
let imgURL: NSURL = NSURL(string: urlString)!
let request: NSURLRequest = NSURLRequest(URL: imgURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request){
(data, response, error) -> Void in
if (error == nil && data != nil) {
func display_image() {
self.imageView.image = UIImage(data: data!)
}
dispatch_async(dispatch_get_main_queue(), display_image)
}
}
task.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
print(currentLegislatorUrl!)
loadRemoteData(currentLegislatorUrl!)
loadImage("https://theunitedstates.io/images/congress/225x275/\(bioguideId!).jpg")
self.title = bioguideId
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath)
cell.textLabel!.text = currentLegislator?.firstName
return cell
}
}
Thanks to Adam H. His comment made me reevaluate the URL I was using and by adding additional operators, now the data is shown in my second ViewController.

Swift - Populating UITableView with data from API

I am trying to set up a feed page with a UITableView, retrieving all the JSON data from Node.js API.
Looks like it it is working, but it is very slow and sometimes does not retrieve all the images. Is there a way to make it work completely, and to optimize 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()
self.tableView.reloadData()
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
println("This is run on the background queue")
self.refreshData()
self.getImage()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println("This is run on the main queue, after the previous code in outer block")
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
if type == 1 {
println("Type= \(type)")
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")
}
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")!
println("request: \(requestURL2)")
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)
//check if exists
let imageUrl = self.imageUrls["url"] as! String
let url = NSURL(string: "http://" + imageUrl)
self.urlsArray.append(url!)
println(self.urlsArray)
}
task2.resume()
}
}
Hi for loading images you can use SDWebImage it will take care of all the heavy lifting and caching for you. here's how:
// Here we use the new provided sd_setImageWithURL: method to load the web image
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {... completion code here ...}];
Here's a Swift example

how do i load 5 rows in UItableview and after scroll down again i will load 5 more rows in swift?

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)
}
}

Resources