UITableViewCell backgroundView image is not downloading & showing right images - ios

I have a customized UITableViewCell with some attributes. The goal is to update each cell with a different background image (downloaded from the web asynchronously). I have ten cells to show, but the problem is that the bottom 5 cells always show the first five images downloaded (thats downloaded for the top 5 cells).
To avoid downloading the images again when a cell reloads when user scrolls, I use a table view cell attribute called isImageLoaded. See the snippet below. Tried multiple solutions to fix this without avail. I do show text attributes for these cells as well (not fetched through HTTP requests) and they show correct values for all the 10 cells scrolling up and down.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:ImageTableCell = self.tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! ImageTableCell
cell.tag = indexPath.section
// cell.imageLoaded is initialized as false in the custom cell settings
if !(cell.imageLoaded) {
var photourl:String = "http://someurl/image" + String(indexPath.section)
downloadImage(cell, url: NSURL(string: photourl)!)
}
}
func downloadImage(cell:HomeSummaryTableCell, url:NSURL){
cell.activityindicator.startAnimating()
println("Started downloading \"\(url.lastPathComponent!.stringByDeletingPathExtension)\".")
getDataFromUrl(url) { data in
dispatch_async(dispatch_get_main_queue()) {
println("Finished downloading \"\(url.lastPathComponent!.stringByDeletingPathExtension)\".")
var imageView:UIImageView = UIImageView(image: UIImage(data: data!))
imageView.contentMode = UIViewContentMode.ScaleAspectFill
imageView.clipsToBounds = true
cell.backgroundView = imageView
cell.activityindicator.stopAnimating()
cell.imageLoaded = true
}
}
}
func getDataFromUrl(urL:NSURL, completion: ((data: NSData?) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(urL) { (data, response, error) in
completion(data: data)
}.resume()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 10
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}

This is happening because dequed cell retains the values of set properties, so you need to reset your imageLoaded parameter when preparing for reuse.
In your custom cell, override prepareForReuse and set imageLoaded to false.
override func prepareForReuse() {
super.prepareForReuse()
imageLoaded = false
}

Related

iOS - Set numberOfSections in tableView to number of filtered cells (Swift)

I've set up my tableView so it filters based on the value of 2 factors of every child of the array (factor1 and factor2) matching with 2 user inputs (factor1UserInput and factor2UserInput). The problem is- because I have my numberOfSections set to return array.count- it loads ALL the cells, including unpopulated cells, for every child in the array.
So, I'm attempting to set my numberOfSections in my tableView to the number of filtered cells (the cells I'm populating) - unless there is a better way to filter these in order to not load unpopulated cells.
numberOfSections code:
func numberOfSections(in tableView: UITableView) -> Int {
return array.count
}
tableView code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath)
let preview = array[indexPath.section]
// BELOW LINE FILTERS THE DATA
if preview.factor1 == factor1UserInput && preview.factor2 == factor2UserInput {
// TRYING TO ONLY LOAD THESE CELLS
print("something matches the filter")
cell.imageView?.image = UIImage(named: "PlaceholderImage")
if let imageUrl = preview.imageUrl {
let url = URL(string: imageUrl)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
cell.imageView?.image = UIImage(data: data!)
}
}.resume()
}
} else {
}
return cell
}
In your case, you should not use the self.array as the source for the tableView, instead, you should declare a proxy variable and use it as the source, something like:
var displayArray: [YourClass] {
return array.filter({ (YourClass) -> Bool in
return /*Your condition here*/
})
}
And then in your table view datasource:
func numberOfSections(in tableView: UITableView) -> Int {
return displayArray.count
}
And then apply the same idea for cellForRowAtIndexPath

Array index out of range - Downloading images from Parse

I am trying to query images from parse, and when I open my app everything works correctly, but if I try and refresh I get this crash shown below...
Not too sure what is causing this...To explain a bit about how I have things set up :
I have a tableView with 1 cell, in that cell are three imageView connected to a collection Outlet. Then I am getting my images from parse and placing them in my imageViews, then in the numberOfRowsInSection I divide it by 3 so it doesn't repeat the image 3 times...!
Here's my code below:
var countries = [PFObject]()
override func viewDidLoad() {
super.viewDidLoad()
loadPosts()
// Do any additional setup after loading the view.
}
func loadPosts() {
PFUser.query()
// Build a parse query object
let query = PFQuery(className:"Post")
query.whereKey("user", equalTo: PFUser.currentUser()!)
query.orderByDescending("createdAt")
// Fetch data from the parse platform
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
// The find succeeded now rocess the found objects into the countries array
if error == nil {
self.countries.removeAll(keepCapacity: true)
if let objects = objects {
self.countries = Array(objects.generate())
}
// reload our data into the collection view
self.tableView.reloadData()
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return countries.count / 3
}
var counter = 0
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell2") as! bdbTableViewCell
for imageView in cell.threeImages {
let placeHolder = UIImage(named: "camera")
imageView.image = placeHolder
let finalImage = countries[counter++]["imageFile"]
finalImage!.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
imageView.image = UIImage(data:imageData)
}
}
}}
return cell
}
If I understand your data, need to move to the spot in the array that has your country's first image, then iterate through the next 3 images.
Basically, you should move the counter declaration inside the function body and initialize it with the location of the first image. See the method definition below for the full implementation.
Your code works the first time by shear luck. Basically iOS will request the cell at row 1, and your counter will increment itself by getting images at index 0,1,and 2. Then iOS will request the cell at row 2, and it will pull images 3,4,5. The counter will keep incrementing. Then, when you refresh the table, the counter is still set to a number higher than the size of your images array, so you get a crash. You would also display image incorrectly if iOS for whatever reason asked for the cells in a different order. You need to use the indexPath.row parameter to get the right images.
Your code also does not account for additional images after the end of a multiple of 3. So if there are 17 images ,images 16 1nd 17 will not be given a row in the tableview. To correct that, add the following function:
func roundUp(value: Double) -> Int {
if value == Double(Int(value)) {
return Int(value)
} else if value < 0 {
return Int(value)
} else {
return Int(value) + 1
}
}
Then change the tableView's numberOfRowsInSection method to the following:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return roundUp(Double(countries.count / 3.0))
}
Finally, in your cellForRowAtIndexPath function, you will have to handle potentially trying to look for an image past the size of your array:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var imageIndex = (indexPath.row * 3)
let cell = tableView.dequeueReusableCellWithIdentifier("cell2") as! bdbTableViewCell
for imageView in cell.threeImages {
let placeHolder = UIImage(named: "camera")
imageView.image = placeHolder
if imageIndex < countries.count
{
let finalImage = countries[imageIndex++]["imageFile"]
finalImage!.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
imageView.image = UIImage(data:imageData)
}
}
}
}
return cell
}
I believe this will fix all of your problems. I do suggest you take a tutorial on how UITableView works, as well as how to step through your own code to troubleshoot. That way you can understand why your original attempt wouldn't work.
var counter = 0
should be reset before function
cellForRowAtIndexPath
Problem
You declared counter variable as static. That's why it is not being reset between cellForRowAtIndexPath calls but it gets incremented each time the method is invoked.
Solution:
Move counter declaration to the function body. Like below:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var counter = 0
let cell = tableView.dequeueReusableCellWithIdentifier("cell2") as! bdbTableViewCell
for imageView in cell.threeImages {
let placeHolder = UIImage(named: "camera")
imageView.image = placeHolder
let finalImage = countries[counter++]["imageFile"]
finalImage!.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
imageView.image = UIImage(data:imageData)
}
}
}}
return cell
}

Reloading table causes flickering

I have a search bar and a table view under it. When I search for something a network call is made and 10 items are added to an array to populate the table. When I scroll to the bottom of the table, another network call is made for another 10 items, so now there is 20 items in the array... this could go on because it's an infinite scroll similar to Facebook's news feed.
Every time I make a network call, I also call self.tableView.reloadData() on the main thread. Since each cell has an image, you can see flickering - the cell images flash white.
I tried implementing this solution but I don't know where to put it in my code or how to. My code is Swift and that is Objective-C.
Any thoughts?
Update To Question 1
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(R.reuseIdentifier.searchCell.identifier, forIndexPath: indexPath) as! CustomTableViewCell
let book = booksArrayFromNetworkCall[indexPath.row]
// Set dynamic text
cell.titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
cell.authorsLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleFootnote)
// Update title
cell.titleLabel.text = book.title
// Update authors
cell.authorsLabel.text = book.authors
/*
- Getting the CoverImage is done asynchronously to stop choppiness of tableview.
- I also added the Title and Author inside of this call, even though it is not
necessary because there was a problem if it was outside: the first time a user
presses Search, the call for the CoverImage was too slow and only the Title
and Author were displaying.
*/
Book.convertURLToImagesAsynchronouslyAndUpdateCells(book, cell: cell, task: task)
return cell
}
cellForRowAtIndexPath uses this method inside it:
class func convertURLToImagesAsynchronouslyAndUpdateCells(bookObject: Book, cell: CustomTableViewCell, var task: NSURLSessionDataTask?) {
guard let coverImageURLString = bookObject.coverImageURLString, url = NSURL(string: coverImageURLString) else {
return
}
// Asynchronous work being done here.
task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
// Update cover image with data
guard let data = data else {
return
}
// Create an image object from our data
let coverImage = UIImage(data: data)
cell.coverImageView.image = coverImage
})
})
task?.resume()
}
When I scroll to the bottom of the table, I detect if I reach the bottom with willDisplayCell. If it is the bottom, then I make the same network call again.
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row+1 == booksArrayFromNetworkCall.count {
// Make network calls when we scroll to the bottom of the table.
refreshItems(currentIndexCount)
}
}
This is the network call code. It is called for the first time when I press Enter on the search bar, then it is called everytime I reach the bottom of the cell as you can see in willDisplayCell.
func refreshItems(index: Int) {
// Make to network call to Google Books
GoogleBooksClient.getBooksFromGoogleBooks(self.searchBar.text!, startIndex: index) { (books, error) -> Void in
guard let books = books else {
return
}
self.footerView.hidden = false
self.currentIndexCount += 10
self.booksArrayFromNetworkCall += books
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
If only the image flash white, and the text next to it doesn't, maybe when you call reloadData() the image is downloaded again from the source, which causes the flash. In this case you may need to save the images in cache.
I would recommend to use SDWebImage to cache images and download asynchronously. It is very simple and I use it in most of my projects. To confirm that this is the case, just add a static image from your assets to the cell instead of calling convertURLToImagesAsynchronouslyAndUpdateCells, and you will see that it will not flash again.
I dont' program in Swift but I see it is as simple as cell.imageView.sd_setImageWithURL(myImageURL). And it's done!
Here's an example of infinite scroll using insertRowsAtIndexPaths(_:withRowAnimation:)
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var dataSource = [String]()
var currentStartIndex = 0
// We use this to only fire one fetch request (not multiple) when we scroll to the bottom.
var isLoading = false
override func viewDidLoad() {
super.viewDidLoad()
// Load the first batch of items.
loadNextItems()
}
// Loads the next 20 items using the current start index to know from where to start the next fetch.
func loadNextItems() {
MyFakeDataSource().fetchItems(currentStartIndex, callback: { fetchedItems in
self.dataSource += fetchedItems // Append the fetched items to the existing items.
self.tableView.beginUpdates()
var indexPathsToInsert = [NSIndexPath]()
for i in self.currentStartIndex..<self.currentStartIndex + 20 {
indexPathsToInsert.append(NSIndexPath(forRow: i, inSection: 0))
}
self.tableView.insertRowsAtIndexPaths(indexPathsToInsert, withRowAnimation: .Bottom)
self.tableView.endUpdates()
self.isLoading = false
// The currentStartIndex must point to next index.
self.currentStartIndex = self.dataSource.count
})
}
// #MARK: - Table View Data Source Methods
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel!.text = dataSource[indexPath.row]
return cell
}
// #MARK: - Table View Delegate Methods
func scrollViewDidScroll(scrollView: UIScrollView) {
if isLoading == false && scrollView.contentOffset.y + scrollView.bounds.size.height > scrollView.contentSize.height {
isLoading = true
loadNextItems()
}
}
}
MyFakeDataSource is irrelevant, it's could be your GoogleBooksClient.getBooksFromGoogleBooks, or whatever data source you're using.
Try to change table alpha value before and after calling [tableView reloadData] method..Like
dispatch_async(dispatch_get_main_queue()) {
self.aTable.alpha = 0.4f;
self.tableView.reloadData()
[self.aTable.alpha = 1.0f;
}
I have used same approach in UIWebView reloading..its worked for me.

Tableview reusing the cells and showing wrong data first

Hello I’ve been having this problem for awhile. I want to stop the tableview from reusing the cell. It keeps displaying the wrong information when i scroll then it shows the right thing like a few milliseconds. How can i stop the tableview from reusing the cell or how can i reuse the cell and make it not do that.
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cats.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "CategoryTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CategoryTableViewCell
cell.nameLabel.text = cats[indexPath.row].categoryName
cell.subNameLabel.text = cats[indexPath.row].appShortDesc
let catImageUrl = cats[indexPath.row].imageUrl
let url = NSURL(string: "https:\(catImageUrl)")
let urlRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in
if error != nil {
print(error)
} else {
if let ass = UIImage(data: data!) {
cell.photoImageView.image = ass
}
self.loading.stopAnimating()
}
}
return cell
}
The problem is that you are seeing an image from a previous cell. Simply initialize the image to nil when you dequeue the reused cell:
cell.photoImageView.image = nil
or set it to a default image of your choosing.
Note, the way you are updating the image after it loads has issues.
The row may no longer be on screen when the image finally loads, so you will be updating a cell that has been reused itself.
The update should be done on the main thread.
A better way to do this would be to have an array that caches the images for the cells. Load the image into the array, and then tell the tableView to reload that row.
Something like this:
dispatch_async(dispatch_get_main_queue()) {
self.imageCache[row] = ass
self.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: row, inSection: 0)],
withRowAnimation: .None)
}
override prepareForReuse() method in your cell class and reset your values
override func prepareForReuse() {
super.prepareForReuse()
nameLabel.text = ""
}
This method is called every time the UITableView before reuses this cell

UITableViewCell image not shown until selected

My UITableViewCells images are displaying until I scroll back upwards whereby the images would not be displayed until the cell is selected.
The same problem also happens when I switch from another ViewController to the initial ViewController*(which contains the image)*
I have checked that the imgURL of the image is correct.
Libraries used are: AFNetworking for the image
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FeedCell", forIndexPath: indexPath) as! MyCell
cell.itemImageView.image = nil
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
// AFNetworking download and display image
func uploadIMG(cell:MyCell,imgURL:NSURL,placeholderIMG:String,atIndexPath indexPath: NSIndexPath) {
var imageRequest: NSURLRequest = NSURLRequest(URL: imgURL)
cell.itemImageView!.setImageWithURLRequest(imageRequest, placeholderImage: UIImage(contentsOfFile: "logo.png"), success: { [weak cell] request,response,image in
if (cell != nil) {
cell!.itemImageView.image = image
}}
, failure: nil)
}
// called from cellForRowAtIndexPath, retrieve img url to update image
func configureCell(cell: MyCell, atIndexPath indexPath: NSIndexPath) {
let item = self.items[indexPath.row] as MWFeedItem
var URLofImage: NSURL = NSURL(string: item.link)!
var session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(URLofImage, completionHandler: {(data,response, error) in
let text = NSString(data: data, encoding: NSUTF8StringEncoding)
var home = HTMLDocument(data: data, contentTypeHeader: text as! String)
var div = home.nodesMatchingSelector("img")
var urlString = div[1].firstNodeMatchingSelector("img")
let urlData = (urlString as HTMLElement).firstNodeMatchingSelector("img")
var urlFinal = urlData.attributes["src"]! as! String
if urlFinal != "/images/system/bookmark-shorturl.png" {
// call updateIMG function
self.uploadIMG(cell, imgURL: NSURL(string: "http:www.animenewsnetwork.com" + urlFinal)!, placeholderIMG: "logo.png",atIndexPath: indexPath)
}
})
Image representation of the problem (Initial image working fine)
Second Image (I scrolled downwards and then scrolled upwards, Image not showing)
I select some cells and the images for those cells will then appear
Try after setting image into cell, update that cell in table view by calling method tableView:reloadRowsAtIndexPaths:withRowAnimation. Or write your custom cell with custom image view. And please, do not forgot that image setting code must run in main thread.
The problem was that my Image wasn't set on the main thread. To solve the problem, I simply used the following code below which ensured that my image will be set immediately.
dispatch_async(dispatch_get_main_queue(), {
// do image functions here
)}
Misread the Question, but keeping this in case anyone has a similar problem, but with autolayout.
I believe you are using autolayout. So if the imageView's frame size is using the intrinsic content size, the size of it's image, it'll be CGSizeZero when there is no image. There is no image when the cell is first displayed, because it needs to be downloaded. So then the image is downloaded and gets assigned to imageView.image. This does not automatically invalidate the layout. You'll need to do that so the imageView frame gets recalculated based on the size of the image. The reason it shows up after scrolling away and scrolling back or selecting it is because the image has been downloaded in that time and the cells layout is recalculated when it gets displayed again or selected.
Below is my TestCell and TestViewController
import UIKit
import AFNetworking
class TestCell : UITableViewCell {
static let cellIdentifier = "TestCell"
#IBOutlet var downloadedImageView: UIImageView!
#IBOutlet var rowLabel: UILabel!
#IBOutlet var statusLabel: UILabel!
}
class TestTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.rowHeight = 100
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(TestCell.cellIdentifier, forIndexPath: indexPath) as! TestCell
let randomName = "\(Random.firstName().lowercaseString).\(Random.lastName().lowercaseString)"
let randomImageURL = NSURL(string: Random.avatarImageURL(name: randomName))!
cell.rowLabel.text = String(indexPath.row)
cell.statusLabel.text = "Not Downloaded"
var imageRequest: NSURLRequest = NSURLRequest(URL: randomImageURL)
cell.downloadedImageView.setImageWithURLRequest(imageRequest, placeholderImage: UIImage(named: "placeholder.png"),
success: { [weak cell]
(request, response, image) in
if let cell = cell {
cell.downloadedImageView.image = image
cell.rowLabel.text = String(indexPath.row)
cell.statusLabel.text = "Downloaded"
}
},
failure: { [weak cell]
(request, response, error) in
if let cell = cell {
cell.downloadedImageView.image = nil
cell.rowLabel.text = String(indexPath.row)
cell.statusLabel.text = "Failed: \(error.localizedDescription)"
}
})
return cell
}
}
//
// Random.swift
import Foundation
class Random {
static let firstNames = ["Tora", "Shasta", "Camelia", "Gertrudis", "Charita", "Donita", "Debbra", "Shaquana", "Tommy", "Shara", "Ignacia", "Cassondra", "Melynda", "Lisette", "Herman", "Rhoda", "Farah", "Tim", "Tonette", "Johnathon", "Debroah", "Britni", "Charolette", "Kyoko", "Eura", "Nevada", "Lasandra", "Alpha", "Mirella", "Kristel", "Yolande", "Nelle", "Kiley", "Liberty", "Jettie", "Zoe", "Isobel", "Sheryl", "Emerita", "Hildegarde", "Launa", "Tanesha", "Pearlie", "Julianna", "Toi", "Terina", "Collin", "Shamika", "Suzette", "Tad"]
static let lastNames = ["Austen", "Kenton", "Blomker", "Demars", "Bibbs", "Eoff", "Alcantara", "Swade", "Klinefelter", "Riese", "Smades", "Fryson", "Altobelli", "Deleeuw", "Beckner", "Valone", "Tarbox", "Shumate", "Tabone", "Kellam", "Dibiase", "Fasick", "Curington", "Holbrook", "Sulzer", "Bearden", "Siren", "Kennedy", "Dulak", "Segers", "Roark", "Mauck", "Horsman", "Montreuil", "Leyva", "Veltz", "Roldan", "Denlinger", "James", "Oriley", "Cistrunk", "Rhodes", "Mcginness", "Gallop", "Constantine", "Niece", "Sabine", "Vegter", "Sarnicola", "Towler"]
class func int(#min: Int, max: Int) -> Int {
return Int(arc4random_uniform(UInt32(max-min))) + min //???: RTFM on arc4random, might be need (max+1)-min.
}
class func int(#range: Range<Int>) -> Int {
return int(min: range.startIndex, max: range.endIndex)
}
class func selectElement<T>(#array: [T]) -> T {
return array[int(range: 0..<array.count)]
}
class func firstName() -> String {
return Random.selectElement(array: Random.firstNames)
}
class func lastName() -> String {
return Random.selectElement(array: Random.lastNames)
}
class func avatarImageURL(var name: String? = nil) -> String {
if name == nil {
name = "(Random.firstName().lowercaseString).Random.lastName().lowercaseString"
}
let avatarImageSize = Random.int(min: 40, max: 285)
return "http://api.adorable.io/avatars/\(avatarImageSize)/\(name!)#gmail.png"
}
class func imageURL() -> String {
let imageWidth = Random.int(min:120, max:1080)
let imageHeight = Random.int(min:120, max:1080)
return "http://lorempixel.com/g/\(imageWidth)/\(imageHeight)/"
}
}
When you scroll, cell will reload. (you reload to redownload your image) -> it's problem.
Solved:
You create array for save image data after download.
And cell get image from this array, not redownload
Hope this helpful!

Resources