Adding image from api to CustomCell programmatically is getting laggy - swift

My tableview gets slow when scrolling, I have a custom cell and a tableview:
I have this controller, where the api call is made and the array of trips is filled, then in cellForRowAt im creating the cell
class HistorialViewController: UIViewController , UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var historialTableView: UITableView!
var trips = [RootClass]()
override func viewDidLoad() {
super.viewDidLoad()
self.historialTableView.delegate = self
self.historialTableView.dataSource = self
self.historialTableView.register(CustomCellHistorial.self, forCellReuseIdentifier: cellId)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("coming back")
self.fetchTrips()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.historialTableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CustomCellHistorial
let trip = self.trips[indexPath.row]
cell.trip = trip
return cell
}
private func fetchTrips(){
AFWrapper.getTripHistory( success: { (jsonResponse) in
self.trips = []
for item in jsonResponse["trips"].arrayValue {
self.trips.append(RootClass(fromJson:item))
}
self.reloadTrips()
Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { (nil) in
self.indicator.stopAnimating()
}
}, failure: { (error) -> Void in
print(error)
})
}
func reloadTrips(){
DispatchQueue.main.async{
self.historialTableView.reloadData()
}
}
This is my CustomCell
class CustomCellHistorial : UITableViewCell{
var trip: RootClass? {
didSet{
dateTimeLabel.text = returnCleanDate(fecha: trip!.createdAt)
distanceAndTimeLabel.text = returnDistanceAndTime(distance: (trip?.trip!.real!.dist!)!, time: (trip?.trip!.real!.time)!)
priceLabel.text = returnCleanPrice(price: (trip?.trip!.real!.price!)!)
ratedLabel.text = "Not Rated"
self.productImage.image = self.returnDriverImage(photoUrl: (self.trip?.driver!.photo!)!)
if (trip!.score) != nil {
let score = trip!.score
if (score?.driver) != nil{
if(trip!.score!.driver!.stars! != 0.0 ){
ratedLabel.isHidden = true
}else{
ratedLabel.isHidden = false
}
}else{
print("yei")
}
}
}
}
private func returnDriverImage(photoUrl: String) -> UIImage{
let url = URL(string: photoUrl)
do {
let data = try Data(contentsOf: url!)
if let roundedimg = UIImage(data: data){
let croppedImageDriver = roundedimg.resize(toTargetSize: self.productImage.frame.size)
return croppedImageDriver
}
} catch let error {
debugPrint("ERRor :: \(error)")
let image = UIImage(named: "perfilIcono")
return image!
}
let image = UIImage(named: "perfilIcono")
return image!
}
Answers that I have found are for older versions of Swift, and the way they make the tableview its in storyboard or they are not handling custom cells.
I think the problem is in the returnDriverImage function.

This line
let data = try Data(contentsOf: url!)
You call from
self.productImage.image = self.returnDriverImage(photoUrl: (self.trip?.driver!.photo!)!)
blocks the main thread and re downloads the same image multiple times when scroll , please consider using SDWebImage

Related

How to Increase count of Page in Url for loading more data and show indicator at bottom?

I Creating a demo of webservices, In this I want to increase page count and load more data from api, and add in table view after activity indicator refreshing. I find many tutorials but Not found useful... They are all Advance and I'm beginner so i didn't get properly. Can Any one please tell how to do this.
Here's My Demo details...
This Is Page Count of URL
"info": {
"count": 826,
"pages": 42,
"next": "https://rickandmortyapi.com/api/character/?page=3",
"prev": "https://rickandmortyapi.com/api/character/?page=1"
},
My json Model
import UIKit
import Foundation
// MARK: - JsonModel
struct JSONModel:Decodable {
let info: Info
let results: [Result]
}
// MARK: - Info
struct Info : Decodable {
let count, pages: Int
let next: String
let prev: NSNull
}
// MARK: - Result
struct Result : Decodable {
let id: Int
let name: String
let status: Status
let species: Species
let type: String
let gender: Gender
let origin, location: Location
let image: String
let episode: [String]
let url: String
let created: String
}
enum Gender {
case female
case male
case unknown
}
// MARK: - Location
struct Location {
let name: String
let url: String
}
enum Species {
case alien
case human
}
enum Status {
case alive
case dead
case unknown
}
This is my View controller Class
import UIKit
import Kingfisher
class ViewController: UIViewController,UISearchBarDelegate{
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
var results = [Results]()
var filteredData = [Results]()
var batchSize = 42
var fromIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
tableView.delegate = self
tableView.dataSource = self
apiCalling()
filteredData = results
}
override func viewWillAppear(_ animated: Bool) {
filteredData = results
self.tableView.reloadData()
}
func apiCalling(){
guard let url = URL(string: "https://rickandmortyapi.com/api/character/") else { return }
URLSession.shared.dataTask(with: url) {[weak self]data, response, error in
if error != nil{
print("error While Fetching Data")
}
guard let data = data else {
return
}
do {
let resultData = try JSONDecoder().decode(JsonModel.self, from: data)
self?.results = resultData.results!
self?.filteredData = self!.results
DispatchQueue.main.async {
self?.tableView.reloadData()
}
} catch {
print(error.localizedDescription)
}
}.resume()
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
let searchText = searchBar.text!
guard !searchText.isEmpty else {
filteredData = results
tableView.reloadData()
return
}
filteredData = results.filter({ $0.name!.lowercased().contains(searchText.lowercased() ) })
tableView.reloadData()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = false
searchBar.text = ""
searchBar.resignFirstResponder()
filteredData.removeAll()
self.tableView.reloadData()
}
}
This My Tableview Extension
extension ViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UserTableViewCell
let row = filteredData[indexPath.row]
let imageUrl = URL(string: row.image!)
cell.userImage.kf.setImage(with: imageUrl)
cell.lblGender.text = "Gender:- \(row.gender ?? "no value")"
cell.lblID.text = "ID:- \(row.id ?? 0)"
cell.lblName.text = "Name: \(row.name!)"
cell.lblSpecies.text = "Species:- \(row.species ?? "No Speies")"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 250
}
}
u need save page info.
self?.info = resultData.info!
call "loadpage" when u loading more data
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
tableView.delegate = self
tableView.dataSource = self
filteredData = []
result = []
apiCalling(apiurl:"https://rickandmortyapi.com/api/character/")
}
func apiCalling(apiurl:String){
guard let url = URL(string: apiurl) else { return }
URLSession.shared.dataTask(with: url) {[weak self]data, response, error in
if error != nil{
print("error While Fetching Data")
}
guard let data = data else {
return
}
do {
let resultData = try JSONDecoder().decode(JsonModel.self, from: data)
self?.results.append(resultData.results!)
self?.info = resultData.info!
filterWord()
} catch {
print(error.localizedDescription)
}
}.resume()
}
func filterWord(){
let searchText = searchBar.text!
guard !searchText.isEmpty else {
filteredData = results
tableView.reloadData()
return
}
filteredData = results.filter({ $0.name!.lowercased().contains(searchText.lowercased() ) })
tableView.reloadData()
}
func loadPage(){
guard let page = self?.info.next,!page.isEmpty else{
return
}
apiCalling(apiurl:page)
}
under indicator simple example like this
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
guard let page = self?.info.next,!page.isEmpty else{
return nil
}
//press to call loadPage
let loading = UIButton.init()
let view = UIView.init()
view.addSubview(loading)
return view
}
I'm Giving My own Questions answer Here...
I Have Create 3 more variables
var curentIndex : Int = 0
// I'm Putting Default Limit Here...
var numberArray = Array(1...42)
var fetchingMore = false
Api Call
func apiCalling(){
guard !fetchingMore else {
print("Didn't call Get Data")
return
}
fetchingMore = true
guard let url = URL( string: "\(baseUrl)?page=\(numberArray[curentIndex])") ?? URL(string: "" ) else {
fetchingMore = false
return
}
curentIndex += 1
URLSession.shared.dataTask(with: url) {[weak self]data, response, error in
if error != nil{
print("error While Fetching Data")
}
guard let data = data else {
return
}
do {
let resultData = try JSONDecoder().decode(JsonModel.self, from: data)
self?.results += resultData.results!
self?.filteredData = self!.results
DispatchQueue.main.async {
self?.tableView.reloadData()
}
} catch {
print(error.localizedDescription)
}
self?.fetchingMore = false
}.resume()
}
**Here's My CellForRowMethod **
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UserTableViewCell
let row = filteredData[indexPath.row]
if indexPath.row == filteredData.count - 1 && curentIndex <= row.id ?? 0 {
apiCalling()
}
let imageUrl = URL(string: row.image!)
cell.userImage.kf.setImage(with: imageUrl)
cell.lblGender.text = "Gender:- \(row.gender ?? "no value")"
cell.lblID.text = "ID:- \(row.id ?? 0)"
cell.lblName.text = "Name: \(row.name!)"
cell.lblSpecies.text = "Species:- \(row.species ?? "No Speies")"
return cell
}

CoreData gets added to Table View AGAIN Every Time I Show View Controller (duplicates data)

I followed this tutorial
https://www.youtube.com/watch?v=35mKM4IkHS8&lc=UgztyK4XjUuAOrKk0XJ4AaABAg.9LtwRc_M0Gv9Nt8GIlAzDo
Basically I made a NotePad App that has a core data save function.
I made this app on another view controller
So There is MainViewController > NoteViewViewController
The first time I click the notepad section it loads core data perfectly well, but if I close out the NoteView and reopen it -- it duplicates all the saved Notes in Core Data
Here is the. Note ViewController
import UIKit
import CoreData
var noteList = [Note]()
class NoteTableView: UITableViewController
{
func nonDeletedNotes() -> [Note]
{
var noDeleteNoteList = [Note]()
for note in noteList
{
if(note.deletedDate == nil)
{
noDeleteNoteList.append(note)
}
}
return noDeleteNoteList
}
var firstLoad = true
override func viewDidLoad() {
if(firstLoad == true)
{
firstLoad = false
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note")
do {
let results:NSArray = try context.fetch(request) as NSArray
for result in results
{
let note = result as! Note
noteList.append(note)
}
}
catch
{
print("Fetch Failed")
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell
{
let noteCell = tableView.dequeueReusableCell(withIdentifier: "noteCellID", for: indexPath) as! NoteCell
let thisNote: Note!
thisNote = nonDeletedNotes()[indexPath.row]
noteCell.titleLabel.text = thisNote.title
noteCell.descLabel.text = thisNote.desc1
return noteCell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return nonDeletedNotes().count
}
override func viewDidAppear(_ animated: Bool) {
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
self.performSegue(withIdentifier: "editNote", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if(segue.identifier == "editNote")
{
let indexPath = tableView.indexPathForSelectedRow!
let noteDetail = segue.destination as? FocusWheelViewController
let selectedNote : Note!
selectedNote = nonDeletedNotes()[indexPath.row]
noteDetail!.selectedNote = selectedNote
tableView.deselectRow(at: indexPath, animated: true)
}
}
}
I'm sure there is a common solution but I'm not sure what it is and wasn't able to follow the posts asking similar questions as my code was different and I truthfully don't understand the mechanics well enough to apply other answers to this
I found the easiest solution was to just add these two lines so the table view refreshed every-time, then loaded the data
noteList.removeAll()
tableView.reloadData()
So the code looks something like this:
var firstLoad = true
override func viewDidLoad() {
if(firstLoad == true)
{
noteList.removeAll() //NEWCODE
tableView.reloadData() //NEWCODE
firstLoad = false
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note")
do {
let results:NSArray = try context.fetch(request) as NSArray
for result in results
{
let note = result as! Note
noteList.append(note)
}
}
catch
{
print("Fetch Failed")
}
}
}
The problem is var firstLoad = true. Because every time the controller start, firtLoad always true and the app will get data from Coredata and append to noteList.
The solution is UserDefaults. The first time when you run app, firstLoad always true. So you need to save the value bool of firstLoad to UserDefaults
// Set
UserDefaults.standard.setValue(true, forKey: "firstLoad")
// Get
UserDefaults.standard.bool(forKey: "firstLoad")
import UIKit
import CoreData
class NoteTableView: UITableViewController{
var noteList = [Note]()
func nonDeletedNotes() -> [Note]{
var noDeleteNoteList = [Note]()
for note in noteList {
if(note.deletedDate == nil) {
noDeleteNoteList.append(note)
}
}
return noDeleteNoteList
}
override func viewDidLoad() {
if noteList.count == 0 {
if(UserDefaults.standard.bool(forKey: "firstLoad") == true){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note")
do {
let results:NSArray = try context.fetch(request) as NSArray
for result in results
{
let note = result as! Note
noteList.append(note)
UserDefaults.standard.setValue(false, forKey: "firstLoad")
}
}
catch {
print("Fetch Failed")
}
}
} {
else {
UserDefaults.standard.setValue(false, forKey: "firstLoad")
}
}
}
}
And maybe you need to check duplicate value when get data from CoreData.

How to update table view

I used search bar. It isn't updating the table view.
struct ApiResults:Decodable {
let resultCount: Int
let results: [Music]
}
struct Music:Decodable {
let trackName: String?
let artistName: String?
let artworkUrl60: String?
}
class ItunesDataViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
var musicArray:[Music] = []
var mArray:[Music] = []
var filteredData:[Music] = []
var isSearching = false
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
self.searchBar.delegate = self
searchBar.placeholder = "search"
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
print("\n\nsearchText : \(searchText)\n\n")
Search(searchTerm: "\(searchText)")
if searchBar.text == nil || searchBar.text == ""
{
isSearching = false
view.endEditing(true)
self.tableView.reloadData()
}
else
{
isSearching = true
filteredData = mArray.filter{$0.artistName == searchText}
self.tableView.reloadData()
}
}
func Search(searchTerm: String)
{
guard let url = URL(string: "https://itunes.apple.com/search?term=\(searchTerm)&attribute=actorTerm&attribute=languageTerm&attribute=allArtistTerm&attribute=tvEpisodeTerm&attribute=shortFilmTerm&attribute=directorTerm&attribute=releaseYearTerm&attribute=titleTerm&attribute=featureFilmTerm&attribute=ratingIndex&attribute=keywordsTerm&attribute=descriptionTerm&attribute=authorTerm&attribute=genreIndex&attribute=mixTerm&attribute=allTrackTerm&attribute=artistTerm&attribute=composerTerm&attribute=tvSeasonTerm&attribute=producerTerm&attribute=ratingTerm&attribute=songTerm&attribute=movieArtistTerm&attribute=showTerm&attribute=movieTerm&attribute=albumTerm") else {return}
URLSession.shared.dataTask(with: url){(data, response, error) in
guard let data = data else {return}
do
{
let apiressults = try JSONDecoder().decode(ApiResults.self, from: data)
for item in apiressults.results
{
if let track_Name = item.trackName, let artist_Name = item.artistName, let artwork_Url60 = item.artworkUrl60
{
let musics = Music(trackName: track_Name, artistName: artist_Name, artworkUrl60: artwork_Url60)
self.musicArray.append(musics)
print(musics.artistName!,"-", musics.trackName!)
}
}
DispatchQueue.main.async
{
self.tableView.reloadData()
}
}
catch let jsonError
{
print("Error:", jsonError)
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching
{
return filteredData.count
}
else
{
return mArray.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell", for: indexPath) as! ItunesDataTableViewCell
if isSearching
{
cell.lblDesc?.text = filteredData[indexPath.row].artistName
cell.lblSongDesc?.text = filteredData[indexPath.row].trackName
let imgString = filteredData[indexPath.row].artworkUrl60!
let imgUrl:URL = URL(string: imgString)!
DispatchQueue.global(qos: .userInitiated).async {
let imageData:NSData = NSData(contentsOf: imgUrl)!
DispatchQueue.main.async {
let image = UIImage(data: imageData as Data)
cell.imgArt?.image = image
}
}
}
else
{
cell.lblDesc?.text = mArray[indexPath.row].artistName
cell.lblSongDesc?.text = mArray[indexPath.row].trackName
let imgString = mArray[indexPath.row].artworkUrl60!
let imgUrl:URL = URL(string: imgString)!
DispatchQueue.global(qos: .userInitiated).async {
let imageData:NSData = NSData(contentsOf: imgUrl)!
DispatchQueue.main.async {
let image = UIImage(data: imageData as Data)
cell.imgArt?.image = image
}
}
}
return cell
}
}
Please clean up your code 😉: You have two different arrays mArray and musicArray.
You are populating musicArray in Search but mArray is used as data source.
Why do you create new Music items from Music items? You can reduce the code to
let apiressults = try JSONDecoder().decode(ApiResults.self, from: data)
self.mArray = apiressults.results
DispatchQueue.main.async {
self.tableView.reloadData()
}
Please change your code in the cellForRowAt delegate method to:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell", for: indexPath) as! ItunesDataTableViewCell
let tempArray: [Music] = isSearching ? filteredData : musicArray
cell.lblDesc?.text = tempArray[indexPath.row].artistName
cell.lblSongDesc?.text = tempArray[indexPath.row].trackName
guard let imgString = tempArray[indexPath.row].artworkUrl60,
let imgUrl = URL(string: imgString) else {
// Handle properly the fact that there's no image to display
return cell
}
// Review this code as I'm not sure about this double dispatch
// However, please, no force unwrap optionals (!)
DispatchQueue.global(qos: .userInitiated).async {
do {
let imageData = try Data(contentsOf: imgUrl)
DispatchQueue.main.async {
let image = UIImage(data: imageData)
cell.imgArt?.image = image
}
} catch let error {
print("Error with the image URL: ", error)
}
}
return cell
}
See how you don't repeat your code that way?
Furthermore you were not using the right music array, or we don't have all the information to assess what is wrong with this mix of mArray and musicArray.

NSOperation for loading image to TableView

Here is my Movie class:
import UIKit
class Movie {
var title: String = ""
var rating: Double = 0
var image: UIImage = UIImage()
}
I want to load the the array of movie to tableView, I have tried like this:
import UIKit
import Cosmos
import Alamofire
//import AlamofireImage
import SwiftyJSON
class Downloader {
class func downloadImageWithURL(url:String) -> UIImage! {
let data = NSData(contentsOfURL: NSURL(string: url)!)
return UIImage(data: data!)
}
}
class MovieViewController: UIViewController, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var movies: [Movie] = []
override func viewDidLoad() {
super.viewDidLoad()
fetchMovies()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MovieTableViewCell
let movie = movies[indexPath.row]
cell.movieTitleLabel.text = movie.title
cell.movieRatingView.rating = Double(movie.rating / 20)
cell.movieImageView.image = movie.image
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func fetchMovies() {
let movieURLString = "https://coderschool-movies.herokuapp.com/movies?api_key=xja087zcvxljadsflh214"
Alamofire.request(.GET, movieURLString).responseJSON { response in
let json = JSON(response.result.value!)
let movies = json["movies"].arrayValue
let queue = NSOperationQueue()
for movie in movies {
let title = movie["title"].string
let rating = movie["ratings"]["audience_score"].double
let imageURLString = movie["posters"]["thumbnail"].string
let movie = Movie()
movie.title = title!
movie.rating = rating!
let operation = NSBlockOperation(block: {
movie.image = Downloader.downloadImageWithURL(imageURLString!)
})
queue.addOperation(operation)
self.movies.append(movie)
self.tableView.reloadData()
}
}
}
}
The problem is that: when I scroll down or up, the images will be reload, otherwise they are not reloaded. Only the title and rating will be
I only know the reason is these line
self.movies.append(movie)
self.tableView.reloadData()
are compiled before
let operation = NSBlockOperation(block: {
movie.image = Downloader.downloadImageWithURL(imageURLString!)
})
queue.addOperation(operation)
But if I scroll down, it will like this:
I've already do it perfectly with AlamofireImage, but I really want to use NSOperation for diving with it.
I think you should make sure to reloadData() on the main thread. By default it's happening on a background thread and cannot update the UI.
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
})
I solved the problem by put the reloadData to the main thread, like so:
let operation = NSBlockOperation(block: {
movie.image = Downloader.downloadImageWithURL(imageURLString!)
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.tableView.reloadData()
}
})
Now it works well.

Wrong indexPathForSelectedRow when using prepareForSegue

I'm trying to fill a tableView with some products from my MySQL database (using a PHP POST file) and at the moment everything is fine, but when I select a "Cell", the prepareForSegue is triggered, but the indexPathForSelectedRow is wrong, so it's showing a different product.
Here is my full code, I hope you can tell me something because I don't know why is this happening, I have tried a lot of things and I'm out of options...!
TableViewController.swift
import UIKit
class ListadoBuscarResultadosTableViewController: UITableViewController {
var option: String = ""
var productos = [Producto]()
var refreshControl2:UIRefreshControl!
var imageCache = [String:UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
requestPost()
title = self.option
tableView.allowsMultipleSelection = true
tableView.scrollsToTop = true
self.tableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.hidesBarsOnSwipe = false
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
func refresh(sender:AnyObject) {
requestPost()
self.refreshControl2.endRefreshing()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return productos.count
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
// Define the initial state (Before the animation)
cell.alpha = 0.25
// Define the final state (After the animation)
UIView.animateWithDuration(1.0, animations: { cell.alpha = 1 })
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// try to reuse cell
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! BuscarCellTableViewCell
cell.selectionStyle = .None
//cell.nombre.text = productos[indexPath.row].nombre
//cell.marca.text = productos[indexPath.row].marca
//println(cell.nombre.text)
// get the deal image
let currentImage = productos[indexPath.row].imagen
let unwrappedImage = currentImage
var image = self.imageCache[unwrappedImage]
let imageUrl = NSURL(string: productos[indexPath.row].imagen)
// reset reused cell image to placeholder
cell.imagen.image = UIImage(named: "")
// async image
if image == nil {
let request: NSURLRequest = NSURLRequest(URL: imageUrl!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
if error == nil {
image = UIImage(data: data)
self.imageCache[unwrappedImage] = image
dispatch_async(dispatch_get_main_queue(), {
cell.imagen.image = image
cell.nombre.text = self.productos[indexPath.row].nombre
cell.marca.text = self.productos[indexPath.row].marca
})
}
else {
cell.nombre.text = self.productos[indexPath.row].nombre
cell.marca.text = self.productos[indexPath.row].marca
}
})
}
else {
cell.imagen.image = image
cell.nombre.text = self.productos[indexPath.row].nombre
cell.marca.text = self.productos[indexPath.row].marca
}
return cell
}
func requestPost () {
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.web.es/productos_by_category.php")!)
request.HTTPMethod = "POST"
let postString = "category="+option
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
//println("error=\(error)")
return
}
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)!
// JSON RESULTADO ENTERO
//println("responseString = \(responseString)")
self.productos = self.parseJsonData(data)
// Reload table view
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
task.resume()
}
func parseJsonData(data: NSData) -> [Producto] {
var productos = [Producto]()
var error:NSError?
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as? NSDictionary
// Return nil if there is any error
if error != nil {
println(error?.localizedDescription)
}
// Parse JSON data
let jsonProductos = jsonResult?["lista_productos"] as! [AnyObject]
for jsonProducto in jsonProductos {
let producto = Producto()
producto.nombre = jsonProducto["nombre"] as! String
producto.imagen = jsonProducto["imagen"] as! String
producto.marca = jsonProducto["marca"] as! String
producto.distribuidor = jsonProducto["distribuidor"] as! String
producto.linea = jsonProducto["linea"] as! String
producto.precio = jsonProducto["precio"] as! String
productos.append(producto)
}
return productos
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "verProducto" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let destinationController = segue.destinationViewController as! MarcaProductoViewController
//println(productos[indexPath.row].nombre)
println(indexPath)
destinationController.nombre = productos[indexPath.row].nombre
}
}
}
Thanks in advance,
Regards.
try this way...
if segue.identifier == "verProducto"{
if let indexPath = tableView.indexPathForCell(sender as! BuscarCellTableViewCell){
var detailsVC = segue.destinationViewController as! MarcaProductoViewController
}
}