Preload Collection View (So that scrolling is smooth) - ios

I would like to be able to preload the items in my collection view when it is being scrolled up and down.
I am using the data of two arrays to load the data in the collection view:
(1) availableLabelNames: [String]
(2) availableImageNames: [String]
Collection View functions in AvailableImages:
class availableImages: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource
{
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var collectionView: UICollectionView!
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return availableLabelNames.count
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) as! CustomCollectionViewCell
cell.borderFolder.layer.borderColor = UIColor.black.cgColor
cell.borderFolder.layer.borderWidth = 2
cell.borderFolder.layer.cornerRadius = 5
cell.squareDesign.layer.cornerRadius = 5
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(availableImages.connected(_:)))
cell.imageCell.isUserInteractionEnabled = true
cell.imageCell.tag = indexPath.row
cell.imageCell.addGestureRecognizer(tapGestureRecognizer)
//setting image
cell.imageCell.image = UIImage(named: availableImageNames[indexPath.row])
//setting label
cell.labelName.text = availableLabelNames[indexPath.row]
return cell
}
}
Custom collection view class:
import UIKit
protocol Normal: class
{
func delete (cell: CustomCollectionViewCell)
func pressed (cell: CustomCollectionViewCell)
func textChanged (cell: CustomCollectionViewCell)
func finishedEditing (cell: CustomCollectionViewCell)
func textStartedEditing (cell: CustomCollectionViewCell)
}
class CustomCollectionViewCell: UICollectionViewCell
{
#IBOutlet weak var imageCell: UIImageView!
#IBOutlet weak var deleteButton: UIButton!
#IBOutlet weak var cellButton: UIButton!
#IBOutlet weak var labelName: UILabel!
#IBOutlet weak var textFieldName: UITextField!
#IBOutlet weak var squareDesign: UIView!
#IBOutlet weak var borderFolder: UIView!
weak var delegate: Normal?
//...class goes on but not important
Please could someone help me I have looked everywhere but nothing seems to work or makes sense in terms of my application.
Thank you so much! :)

Collection view is doing preloading by default. Your problem is elsewhere, you can't do heavy work in cell for item.
Would need a sample project to try it on, but I would bet this is the root of the problem:
cell.imageCell.image = UIImage(named: availableImageNames[indexPath.row])
rewrite it to this:
DispatchQueue.main.async { [weak self] in
guard let weakSelf = self else { return }
cell.imageCell.image = UIImage(named: weakSelf.availableImageNames[indexPath.row])
}
Also, as cells are reused, you want to reset their image. Otherwise, images will be shown randomly.

Related

Cells in tableview are compressed and shrunk

2 days ago I started developing an APP as a school project with Swift and Storyboard.
Now I've started to use UITableViews and also have Cells design, but somehow they are generated and reduced in size and I don't understand exactly why.
How i designed it:
How it looks:
I wrote these costum subclass for the Cell:
import UIKit
class ContentView: UITableViewCell {
#IBOutlet weak var CellPriority: UILabel!
#IBOutlet weak var FromCell: UILabel!
#IBOutlet weak var CellTime: UILabel!
#IBOutlet weak var CellDesc: UILabel!
#IBOutlet weak var CellTitle: UILabel!
#IBOutlet weak var CellImage: UIImageView!
}
and this is my ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var ContentTable: UITableView!
var ContentArray = [ContentView]()
override func viewDidLoad() {
super.viewDidLoad()
ContentTable.dataSource = self
ContentTable.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}
var titleArray = ["asd", "bsd", "csd", "dsd", "esd", "fsd", "gsd", "hsd", "isd", "jsd", "ksd", "lsd", "msd", "nsd", "osd", "psd", "qsd", "rsd", "ssd", "tsd", "usd", "vsd", "wsd", "xsd", "ysd", "zsd"]
var descArray = ["asd", "bsd", "csd", "dsd", "esd", "fsd", "gsd", "hsd", "isd", "jsd", "ksd", "lsd", "msd", "nsd", "osd", "psd", "qsd", "rsd", "ssd", "tsd", "usd", "vsd", "wsd", "xsd", "ysd", "zsd"]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ContentTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ContentView
let image = UIImage(named:"")
cell.CellImage.image = image
cell.CellTitle.text = titleArray[indexPath.row]
cell.CellDesc.text = descArray[indexPath.row]
cell.CellTime.text = "resultE"
cell.CellPriority.text = "!!!"
cell.FromCell.text = "lol"
return cell
}
}
(I have everything else which is unnecessary, regarding the problem, has been deleted)
(These were things like the "erstellen" button and so on.)
Thank you very much

How to debug "unrecognized selector sent to instance" in Swift while the method is not implemented

I have 2 UITextFields in my current view controller. The problem I encounter is when I finish typing in one TextField and try to move the cursor to the other, my app crashed.
I've set up my view controller to implement UITextFieldDelegate. Set the delegate of the two TextFields to be self and implement the textFieldShouldReturn method.
The error message I got is:
[Snapagram.SnapViewController disableEditing:]: unrecognized selector
sent to instance 0x7fabdc55d700.
What I've tried is to use Exception breakpoint, but it only returns to the 1st line of AppDelegate. So I don't know which part of my code to post. Plus, I don't even have disableEditing anywhere in my code. My question are
how can I see which object is calling this method
why is this method being called, despite me not having implemented it
Edit:
this is the entire view controller code, the textFieldShouldReturn is at the bottom.
import UIKit
class SnapViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var chosenThread: Thread!
var entry: ThreadEntry!
var post: Post!
var imageToDisplay: UIImage!
#IBOutlet weak var threadCollectionView: UICollectionView!
#IBOutlet weak var createButton: UIButton!
#IBOutlet weak var imageDisplayed: UIImageView!
#IBOutlet weak var captionField: UITextField!
#IBOutlet weak var locationField: UITextField!
#IBOutlet weak var postButton: UIButton!
override func viewDidLoad() {
imageDisplayed.image = imageToDisplay!
super.viewDidLoad()
postButton.layer.cornerRadius = 25.0
createButton.layer.cornerRadius = 25.0
threadCollectionView.delegate = self
threadCollectionView.dataSource = self
captionField.delegate = self
locationField.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return feed.threads.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let index = indexPath.item
let thread = feed.threads[index]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "chooseThreadCell", for: indexPath) as? ChooseThreadCollectionViewCell {
cell.emojiLabel.text = thread.emoji
cell.nameLabel.text = thread.name
return cell
} else {
return UICollectionViewCell()
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
chosenThread = feed.threads[indexPath.item]
entry = ThreadEntry(username: feed.username, image: imageToDisplay)
}
#IBAction func createPressed(_ sender: UIButton) {
chosenThread.addEntry(threadEntry: entry)
}
#IBAction func postPressed(_ sender: Any) {
post = Post(location: locationField.text!, image: imageToDisplay, user: feed.username, caption: captionField.text!, date: Date())
feed.addPost(post: post)
}
}
extension SnapViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return true
}
}

Having trouble connecting my CustomCell.xib to my tableView in the storyboard

I Have to do an app for recipes and it shows me different recipes in my tableView, and i just want to implement my CustomCell (from a xib file) to my storyboard and I don't know how to connect it to show my data (I already checked my identifier) here's the code of my controller :
class SearchRecipe: UIViewController, ShowAlert {
var recipeData = RecipeDataModel()
var recipe = [String]()
#IBOutlet weak var tableViewSearch: UITableView!
override func viewDidLoad() {
self.tableViewSearch.rowHeight = 130
}
func updateRecipeData(json: JSON){
if let ingredients = json["hits"][0]["recipe"]["ingredientLines"].arrayObject{
recipeData.ingredientsOfRecipe = ingredients[0] as! String
recipeData.cookingTime = json["hits"][0]["recipe"]["totalTime"].stringValue
recipeData.recipe = json["hits"][0]["recipe"]["label"].stringValue
recipeData.recipeImage = json["hits"][0]["recipe"]["image"].stringValue
}
else {
print("Problem")
}
//self.tableViewSearch.reloadData()
}
}
extension SearchRecipe: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipe.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customRecipeCell", for: indexPath) as! CustomRecipeCell
getRecipesDisplay(in: cell, from: recipeData , at: indexPath)
return cell
}
func getRecipesDisplay(in cell: CustomRecipeCell, from recipeModel: RecipeDataModel, at indexPath: IndexPath){
cell.recipeTitle.text = recipeData.recipe
cell.recipeInfos.text = recipeData.ingredientsOfRecipe
cell.timerLabel.text = recipeData.cookingTime
}
}
and this is the code my xib file :
class CustomRecipeCell: UITableViewCell {
#IBOutlet weak var recipeTitle: UILabel!
#IBOutlet weak var recipeInfos: UILabel!
#IBOutlet weak var cellImageBackground: UIImageView!
#IBOutlet weak var likeAndTimerView: UIView!
#IBOutlet weak var likeImage: UIImageView!
#IBOutlet weak var timerImage: UIImageView!
#IBOutlet weak var likeLabel: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func awakeFromNib() {
super.awakeFromNib()
activityIndicator.isHidden = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
In ViewDidLoad, you must register your cell this way:
override func viewDidLoad() {
tableViewSearch.register(UINib(nibName:" /* NAME OF YOUR XIB FILE */ ", bundle: nil), forCellReuseIdentifier: "customRecipeCell")
}
You also have to edit the size of your cell in the attribute inspector of your custom cell and of your table view

Swift -> my prototype cell (UITableViewCell) doesn't show in my UIViewController with a UITableView

My storyboard looks like this
and my code is the following
UIViewController
class DownLoadSoundsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: View Controller Properties
let viewName = "DownLoadSoundsViewController"
#IBOutlet weak var visualEffectView: UIVisualEffectView!
#IBOutlet weak var dismissButton: UIButton!
#IBOutlet weak var downloadTableView: UITableView!
// MARK: Properties
var soundPacks = [SoundPack?]() // structure for downloadable sounds
override func viewDidLoad() {
super.viewDidLoad()
downloadTableView.dataSource = self
downloadTableView.delegate = self
downloadTableView.register(DownLoadTableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfSoundPacks
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let method = "tableView.cellForRowAt"
//if (indexPath as NSIndexPath).section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "downloadTableViewCell", for: indexPath) as! DownLoadTableViewCell
cell.backgroundColor = UIColor.green
if soundPacks[(indexPath as NSIndexPath).row]?.price == 0 {
cell.soundPackPriceUILabel.text = "FREE"
} else {
cell.soundPackPriceUILabel.text = String(format: "%.2", (soundPacks[(indexPath as NSIndexPath).row]?.price)!)
}
//cell.textLabel?.text = soundPacks[(indexPath as NSIndexPath).row]?.soundPackTitle
cell.soundPackTitleUILabel.text = soundPacks[(indexPath as NSIndexPath).row]?.soundPackTitle
cell.soundPackAuthorUILabel.text = soundPacks[(indexPath as NSIndexPath).row]?.author
cell.soundPackShortDescription.text = soundPacks[(indexPath as NSIndexPath).row]?.shortDescription
cell.soundPackImage.image = UIImage(named: "Placeholder Icon")
DDLogDebug("\(viewName).\(method): table section \((indexPath as NSIndexPath).section) row \((indexPath as NSIndexPath).row))")
return cell
//}
}
UItableViewCell
class DownLoadTableViewCell: UITableViewCell {
#IBOutlet weak var soundPackImage: UIImageView!
#IBOutlet weak var soundPackTitleUILabel: UILabel!
#IBOutlet weak var soundPackAuthorUILabel: UILabel!
#IBOutlet weak var soundPackShortDescription: UILabel!
#IBOutlet weak var soundPackPriceUILabel: UILabel!
let gradientLayer = CAGradientLayer()
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
}
}
But I get the following;
I am sure I am doing something small incorrectly, but as of yet can't figure it out. Looked through many examples included my own code where I have gotten this working before.
Not a single one of my settings for the tableview are getting invoked except the number of cells. But everything in;
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{...}
is not working.
Help is appreciated.
I think you need to reload the tableView after getting data from Firebase
self.saveMixesTableView.reloadData()

iOS - should the UIView or the UIViewController handle the state to UI mapping?

I've read a few posts but I could not find a clear answer to this question: in the MVC framework, who should be responsible for the UI set up? I'm balancing between two options:
class ViewController: UITableViewController {
private var users: [User]
...
override func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = dequeueDataCell(id: "myCell") as? CellView else { return UITableViewCell() }
cell.title.text = user?.name
cell.subtitle.text = user?.nickname
cell.action.isHidden = isSelected
// other numerous UI set up on the cell
return cell
}
}
class CellView: UITableViewCell {
#IBOutlet weak var title: UILabel?
#IBOutlet weak var subtitle: UILabel?
#IBOutlet weak var action: UIButton!
}
and
class ViewController: UITableViewController {
private var users: [User]
...
override func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = dequeueDataCell(id: "myCell") as? CellView else { return UITableViewCell() }
cell.user = self.users[indexPath.row]
cell.isSelected = false
cell.refresh()
return cell
}
}
class CellView: UITableViewCell {
#IBOutlet private weak var title: UILabel?
#IBOutlet private weak var subtitle: UILabel?
#IBOutlet private weak var action: UIButton!
weak var user: User?
var isSelected = false
func refresh() {
title.text = user?.name
subtitle.text = user?.nickname
action.isHidden = isSelected
// other numerous UI set up on the cell
}
}
I've so far been using the first approach that is found in most iOS tutorials. But I've found that this makes the UIViewController much longer, while they already have a tendency to become long and obscure, and harder to read since it mixes UI and state logic.

Resources