Table View Lag (even after removing gesture recognizers) - swift

Currently, I have a table view that lags when there are multiple cells. When there is only one cell, it performs smoothly; however, when multiple cells are populated, the table view has a slow feeling, sometimes stutters, and is not as smooth. I removed the gesture recognizers and instead changed it to didSelectRowAt, however there is still lag within the cells. Here is the code for the when the cells are loaded :
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if queryComplete == true {
if displayConvo == true {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath as IndexPath) as! messageTableViewCell
cell.profileImage.image = nil
cell.selectionStyle = UITableViewCell.SelectionStyle.none
var convoContent: messagesViewController.Convo
convoContent = convoList[indexPath.row]
convoContent.itemHeroID = "\(String(describing: convoContent.convoID))"
cell.name.heroID = "\(String(describing: convoContent.convoID))"
cell.lastMessage.text = convoContent.lastMessage
cell.backgroundColor = UIColor.clear
cell.postText.text = convoContent.postContent
if convoContent.revealedBool == true {
cell.profileImage.isHidden = false
cell.profileImage.heroID = "\(String(describing: convoContent.convoID))"
cell.name.text = convoContent.name
cell.timer.isHidden = true
if convoContent.profileImage == "nil" || convoContent.profileImage == nil {
let url = URL(string:"https://firebasestorage.googleapis.comasdjfjaisfdji")
let processor = RoundCornerImageProcessor(cornerRadius: cell.profileImage.frame.size.width / 2)
cell.profileImage.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])
}
else {
let url = URL(string: convoContent.profileImage!)
let processor = RoundCornerImageProcessor(cornerRadius: cell.profileImage.frame.size.width / 2)
cell.profileImage.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])
}
}
else {
cell.profileImage.isHidden = true
cell.timer.isHidden = false
cell.timer.isUserInteractionEnabled = false
cell.timer.heroID = "\(String(describing: convoContent.convoID))"
let postDuration = convoContent.timeOfDeletion! - Int(convoContent.time!)
let currentTime = Date().timeIntervalSince1970 * 1000
let difference = Int(round(Double(convoContent.timeOfDeletion! - Int(currentTime))))
let date = Date(timeIntervalSinceNow: TimeInterval(difference / 1000))
cell.name.text = String(timeToDelete(date: date as NSDate, numericDates: false))
let amountOfCircleCovered = (Double(((convoContent.timeOfDeletion!) - Int(currentTime))) / Double(postDuration)) * 100
var timerColor: UIColor?
switch amountOfCircleCovered {
case 0..<30:
timerColor = UIColor (red: 252/255, green: 110/255, blue: 81/255, alpha: 1)
case 30..<60:
timerColor = UIColor (red: 255/255, green: 215/255, blue: 0/255, alpha: 1)
case 60..<100:
timerColor = UIColor(red: 26/255, green: 152/255, blue: 252/255, alpha: 1.0)
default:
timerColor = UIColor(red: 26/255, green: 152/255, blue: 252/255, alpha: 1.0)
}
print(amountOfCircleCovered)
cell.timer.models = [ PieSliceModel(value: Double(100 - amountOfCircleCovered), color: UIColor(red: 220/255, green: 220/255, blue: 220/255, alpha: 1)),
PieSliceModel(value: Double(amountOfCircleCovered), color: timerColor!),
]
}
let lastMessageDate = Date(timeIntervalSince1970: TimeInterval(convoContent.timeOfLastMessage! / 1000))
cell.timeOfLastMessage.text = String(timeAgo(date: lastMessageDate as NSDate, numericDates: false))
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath as IndexPath) as! messageTableViewCell
cell.lastMessage.text = "No new messages"
return cell
}
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath as IndexPath) as! messageTableViewCell
print ("loading")
return cell
}
}
Additionally, I have tried moving some of the aspects of the cell so they can be reset each time by putting them in the cell file:
override func awakeFromNib() {
super.awakeFromNib()
profileImage.cornerRadius = profileImage.frame.size.width / 2
profileImage.clipsToBounds = true
profileImage.layer.borderColor = UIColor.white.cgColor
profileImage.layer.borderWidth = 1
timer.innerRadius = 0
timer.outerRadius = timer.frame.width / 2
timer.animDuration = 0.0
timer.referenceAngle = 270
timer.backgroundColor = UIColor.white
postText.layer.zPosition = 1
if !UIAccessibility.isReduceTransparencyEnabled {
glossyView.backgroundColor = .clear
let blurEffect = UIBlurEffect(style: .regular)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = self.glossyView.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
glossyView.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
} else {
glossyView.backgroundColor = .black
}
timer.selectedOffset = 0
glossyView.clipsToBounds = true
glossyView.cornerRadius = 12.0
glossyView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
messageBackground.clipsToBounds = true
messageBackground.cornerRadius = 12.0
messageBackground.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
// glossyView.roundCornersView(corners: [.topLeft, .topRight], radius: 12.0)
// messageBackground.roundCornersView(corners: [.bottomLeft,.bottomRight], radius: 12.0)
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
profileImage.image = nil
timer.isHidden = true
timer.models = []
}
}
And yet, when multiple cells are loaded, the table view still lags. I made sure there are no gesture recognizers as this link suggests and also the images are being loaded using a library so I am not sure why the cells still lag.

Essentially, the UI was dramatically slowing down the performance. I switched out the pie time CA Layer for png images of circles partially filled, and removed all Hero animations. As a result, both the app and tableview became much smoother.

Related

Place gradient color inside UIView in tableViewCell

I have added two views inside a stack view. I am having that stack view inside my tableViewCell. Now my stackView is placed in the centre of the content view with width and height. I want to apply gradient color inside my view which is inside my stackView .
Just look at the view below In this case I am giving view a background colour of red and green which I don't want. I want to apply gradient of four colours to this views.
enter image description here
Here is the code of a simple progress bar that I have written in Swift:
import Foundation
import Cocoa
public class GradientProgressView : NSView
{
// MARK: - Fields
private let bgLayer = CAShapeLayer()
private var progressLayer = CAShapeLayer()
private var gradientLayer = CAGradientLayer()
private var blockLayer = CAShapeLayer()
private var mValue: CGFloat = 0.0
// MARK: - Properties
public var colors: [NSColor] = [NSColor.systemGreen, NSColor.systemYellow, NSColor.sytemRed]
public var value: CGFloat
{
set
{
self.mValue = newValue
if self.mValue > 1.0
{
self.mValue = 1.0
}
if self.mValue < 0.0 || self.mValue.isNaN || self.mValue.isInfinite
{
self.mValue = 0.0
}
self.progressLayer.strokeEnd = self.mValue
}
get
{
return self.mValue
}
}
// MARK: - Overrides
public override func layout()
{
super.layout()
self.initialize()
}
// MARK: - Helper
fileprivate func initialize()
{
self.wantsLayer = true
self.layer?.masksToBounds = true // Optional
self.layer?.cornerRadius = self.bounds.height / 2.0 // Optional
self.bgLayer.removeFromSuperlayer()
self.bgLayer.contentsScale = NSScreen.scale
self.bgLayer.fillColor = NSColor.separatorColor.cgColor
self.bgLayer.path = NSBezierPath(rect: self.bounds).cgPath
self.layer?.addSublayer(self.bgLayer)
self.blockLayer.removeAllAnimations()
self.blockLayer.removeFromSuperlayer()
let path = NSBezierPath()
path.move(to: CGPoint(x: self.bounds.height / 2.0, y: self.bounds.height / 2.0))
path.line(to: CGPoint(x: self.bounds.width - self.bounds.height / 2.0, y: self.bounds.height / 2.0))
self.progressLayer.path = path.cgPath
self.progressLayer.strokeColor = NSColor.black.cgColor
self.progressLayer.fillColor = nil
self.progressLayer.lineWidth = self.bounds.height
self.progressLayer.lineCap = .round
self.progressLayer.strokeStart = 0.0
self.progressLayer.strokeEnd = 0.0
self.progressLayer.contentsScale = NSScreen.scale
self.gradientLayer.removeAllAnimations()
self.gradientLayer.removeFromSuperlayer()
self.gradientLayer.contentsScale = NSScreen.scale
self.gradientLayer.colors = self.colors.map({ $0.cgColor })
self.gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
self.gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
self.gradientLayer.mask = self.progressLayer
self.gradientLayer.frame = self.bounds
self.gradientLayer.contentsScale = NSScreen.scale
self.layer?.addSublayer(self.gradientLayer)
}
}
This progress bar supports multiple colors.
Simply replace your progress bar logic with the one I posted above (or add the logic for the triangle that is shown below the progress bar).
Preview:
Create GradientLayer on your tableViewCell(collectionViewCell)
1. Create CAGradientLayer Instance on your tableViewCell
class MyCell: UITableViewCell {
let gradientLayer = CAGradientLayer()
}
2. Set the layer frame to view's bounds from layoutSublayers(of:)
If you set your layer's frame some other place, frame becomes weird.
class MyCell: UITableViewCell {
let gradientLayer = CAGradientLayer()
// Setting it from layoutSubViews also fine.
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: self.layer)
gradientLayer.frame = yourView.bounds
}
}
3. Add GradientLayer on the View.
Here is my UIView extension for adding gradient layer.
extension UIView {
func addGradient(with layer: CAGradientLayer, gradientFrame: CGRect? = nil, colorSet: [UIColor],
locations: [Double], startEndPoints: (CGPoint, CGPoint)? = nil) {
layer.frame = gradientFrame ?? self.bounds
layer.frame.origin = .zero
let layerColorSet = colorSet.map { $0.cgColor }
let layerLocations = locations.map { $0 as NSNumber }
layer.colors = layerColorSet
layer.locations = layerLocations
if let startEndPoints = startEndPoints {
layer.startPoint = startEndPoints.0
layer.endPoint = startEndPoints.1
}
self.layer.insertSublayer(layer, above: self.layer)
}
}
* Option 1 - Add it from layoutSublayers(of:)
class MyCell: UITableViewCell {
let gradientLayer = CAGradientLayer()
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: self.layer)
gradientLayer.frame = yourView.bounds
let colorSet = [UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1.0),
UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0)]
let location = [0.2, 1.0]
yourView.addGradient(with: gradientLayer, colorSet: colorSet, locations: location)
}
}
* Option 2 - Add it from cellForRowAt
For example, if we have cellForRowAt and like this,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellId", for: indexPath) as? MyCell {
cell.configureCell(content: someItems[indexPath.row])
}
return UITableViewCell()
}
Now, we can handle gradientLayer from configureCell(content:).
class MyCell: UITableViewCell {
let gradientLayer = CAGradientLayer()
func configureCell(content: YourType) {
let colorSet = [UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1.0),
UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0)]
let location = [0.2, 1.0]
yourView.addGradient(with: gradientLayer, colorSet: colorSet, locations: location)
}
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: self.layer)
gradientLayer.frame = yourView.bounds
}
}

RGB slider color showing in grayscale instead of in color

I'm making a RGB slider programmatically and I've come across an issue where I can't seem to figure out how to properly show the color of each sliders' values as a UIColor. I've gotten as far as changing the colors in the box, but they come out grayscale and I don't understand why.
View class:
extension UIView {
func colorSlider(tintColor: UIColor) -> UISlider {
let slider = UISlider()
slider.minimumValue = 0
slider.maximumValue = 255
slider.isContinuous = true
slider.tintColor = tintColor
slider.frame.size = CGSize(width: 250, height: 20)
return slider
}
}
class SliderView: UIView {
let stackView: UIStackView
let redColorSlider = UIView().colorSlider(tintColor: .red)
let greenColorSlider = UIView().colorSlider(tintColor: .green)
let blueColorSlider = UIView().colorSlider(tintColor: .blue)
let previewColorButton: UIButton = {
let button = UIButton()
button.frame.size = CGSize(width: 80, height: 100)
return button
}()
override init(frame: CGRect) {
self.stackView = UIStackView(arrangedSubviews: [redColorSlider, greenColorSlider, blueColorSlider])
stackView.distribution = .fillEqually
stackView.spacing = 15
stackView.axis = .vertical
super.init(frame: frame)
setupLayout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupLayout() {
backgroundColor = .white
addSubview(previewColorButton)
previewColorButton.anchor(left: leftAnchor, paddingLeft: 20, width: 80, height: 100)
previewColorButton.centerY(inView: self)
addSubview(stackView)
stackView.anchor(left: previewColorButton.rightAnchor, paddingLeft: 20, paddingRight: 20, width: 250)
stackView.centerY(inView: self)
}
}
Controller class:
class SliderController: UIViewController {
let sliderView = SliderView()
let step: Float = 0.1
let redLabel = UIView().rgbLabel()
var redValue: CGFloat = 0
let greenLabel = UIView().rgbLabel()
var greenValue: CGFloat = 0
let blueLabel = UIView().rgbLabel()
var blueValue: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
view = sliderView
redLabel.text = "0"
greenLabel.text = "0"
blueLabel.text = "0"
sliderView.previewColorButton.backgroundColor = .blue
sliderView.redColorSlider.addTarget(self, action: #selector(sliderValueChanged(sender:)), for: .valueChanged)
sliderView.greenColorSlider.addTarget(self, action: #selector(sliderValueChanged(sender:)), for: .valueChanged)
sliderView.blueColorSlider.addTarget(self, action: #selector(sliderValueChanged(sender:)), for: .valueChanged)
sliderView.previewColorButton.addTarget(self, action: #selector(sliderValueChanged(sender:)), for: .valueChanged)
let stackView = UIStackView(arrangedSubviews: [redLabel, greenLabel, blueLabel])
stackView.distribution = .fillEqually
stackView.spacing = 5
view.addSubview(stackView)
stackView.anchor(bottom: view.safeAreaLayoutGuide.bottomAnchor)
stackView.centerX(inView: view)
}
#objc func sliderValueChanged(sender: UISlider) {
redValue = CGFloat(round(sender.value / step) * step)
greenValue = CGFloat(round(sender.value / step) * step)
blueValue = CGFloat(round(sender.value / step) * step)
redLabel.text = "\(Int(redValue))"
greenLabel.text = "\(Int(greenValue))"
blueLabel.text = "\(Int(blueValue))"
sliderView.previewColorButton.backgroundColor = UIColor(red: redValue/255, green: greenValue/255, blue: blueValue/255, alpha: 1.0)
}
I've tried separating the slider action function #objc func sliderValueChanged to each individual slider action like so:
#objc func redSliderValueDidChange(sender: UISlider) {
let redSliderValue = round(sender.value / step) * step
redValue = CGFloat(redSliderValue)
redLabel.text = "\(Int(redValue))"
}
#objc func greenSliderValueDidChange(sender: UISlider) {
let greenSliderValue = round(sender.value / step) * step
greenValue = CGFloat(greenSliderValue)
greenLabel.text = "\(Int(greenValue))"
}
#objc func blueSliderValueDidChange(sender: UISlider) {
let blueSliderValue = round(sender.value / step) * step
blueValue = CGFloat(blueSliderValue)
blueLabel.text = "\(Int(blueValue))"
}
This helps so that each color label changes individually, as opposed to what I have above, but the colors don't change.
How it looks currently:
I haven't found any information on how to do this programmatically, so any help is appreciated!
Please check the targets you have added to the slider.
Also, you can replace the following method in your code:
#objc func sliderValueChanged(sender: UISlider)
{
sliderView.previewColorButton.backgroundColor = UIColor(red: CGFloat(redSliderValue/255), green: CGFloat(greenSliderValue/255), blue: CGFloat(blueSliderValue/255), alpha: 1.0)
}

How to pass data from UITableView to UIViewController without segue

I need to pass the title of Row in UITableView to my ViewController. I don't have VC in storyboard (I've created it by code). So I can't use segue.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! UITableViewCell
cell.textLabel?.textColor = UIColor(red: 0, green: 122/255, blue: 1, alpha: 1)
cell.textLabel?.tintColor = UIColor(red: 0, green: 122/255, blue: 1, alpha: 1)
var titleOfFood = String()
if searching == true {
titleOfFood = searchedFoods[indexPath.row].title
cell.textLabel?.textColor = UIColor(red: 0, green: 122/255, blue: 1, alpha: 1)
print(titleOfFood)
} else {
titleOfFood = foods[indexPath.row].title
cell.textLabel?.textColor = UIColor(red: 0, green: 122/255, blue: 1, alpha: 1)
print(titleOfFood)
}
let controller = EatenFoodViewController()
let transitionDelegate = SPStorkTransitioningDelegate()
controller.transitioningDelegate = transitionDelegate
controller.modalPresentationStyle = .custom
//controller.delegate = self
transitionDelegate.customHeight = 620
transitionDelegate.showIndicator = false
self.present(controller, animated: true, completion: nil)
}
I need to pass titleOfFood to EatenFoodViewController
You don't need to have a segue to send data to the destination vc , you can simply do
controller.titleOfFood = arr[indexPath.row].title // assuming you have an array of models
OR
controller.titleOfFood = cell.textLabel!.text!
class EatenFoodViewController:UIViewController {
var titleOfFood = ""
}

Cannot unselect the checkmark when scroll the tableView

I'm trying to do checkmark button in tableViewCell. The checkmark image will be hide/showing when user tap on the checkmark button. The problem I'm facing right now is checkmark button acting weird when I scroll the table view which is I need to double tap to unselect the checkmark.
When I do not scroll the tableView it's working great. Below are the video and code. Thanks in advance.
https://youtu.be/cQBIuIXJlRY
func tableView(_ tableView: UITableView, cellForRowAt
indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dtvc") as! DeviceTableViewCell
let scannedDevice = devices[indexPath.row]
// Set the tag & addTarget for addButton
cell.addButton.addTarget(self, action: #selector(addButtonTapped), for: .touchUpInside)
cell.addButton.isEnabled = true
cell.addButton.tag = indexPath.row
cell.configureCell(with: scannedDevice)
cell.isSelected = checked[indexPath.row] ?? false
print("cell isSelected at \(indexPath.row) cellForRow \(cell.isSelected)")
print("checked value at \(indexPath.row) is \(checked[indexPath.row])")
if checked[indexPath.row] == true {
cell.deviceMake.textColor = UIColor.white
cell.backgroundColor = UIColor(red: 233/255, green: 72/255, blue: 85/255, alpha: 1)
cell.addButton.setImage(UIImage(named: "Checkmark"), for: .normal)
cell.addButton.bgColor = UIColor.green
} else {
cell.deviceMake.textColor = UIColor.gray
cell.backgroundColor = UIColor.clear
cell.addButton.setImage(nil, for: .normal)
cell.addButton.bgColor = UIColor(red: 233/255, green: 72/255, blue: 85/255, alpha: 1)
}
return cell
}
#objc func addButtonTapped(_ sender: UIButton) {
let indexPath = IndexPath(row: sender.tag, section: 0)
let scannedDevice = devices[sender.tag]
let cell = tableView.cellForRow(at: indexPath) as! DeviceTableViewCell
cell.isSelected = !cell.isSelected
print("cell.isSelected is at button \(sender.tag) tapped is \(cell.isSelected)")
if cell.isSelected == true {
// Main color RGB is 233,72,85 ... hex is E94855
cell.deviceMake.textColor = UIColor.white
cell.backgroundColor = UIColor(red: 233/255, green: 72/255, blue: 85/255, alpha: 1)
cell.addButton.setImage(UIImage(named: "Checkmark"), for: .normal)
cell.addButton.bgColor = UIColor.green
checked[sender.tag] = cell.isSelected
print("Checked 1 at tag \(sender.tag) is \(checked[sender.tag])")
//show selectedDeviceView
if selectedDeviceView.isHidden {
UIView.animate(withDuration: 2.5, delay: 0.7, options: .curveEaseInOut, animations: {
self.tableViewHeightConstraint.constant = self.tableViewHeightConstraint.constant - self.selectedDeviceViewTopConstraint.constant - self.selectedDeviceView.frame.height
self.selectedDeviceViewTopConstraint.constant = 0
self.selectedDeviceView.isHidden = false
}, completion: nil)
}
}
else {
cell.deviceMake.textColor = UIColor.gray
cell.backgroundColor = UIColor.clear
cell.addButton.setImage(nil, for: .normal)
cell.addButton.bgColor = UIColor(red: 233/255, green: 72/255, blue: 85/255, alpha: 1)
checked[sender.tag] = cell.isSelected
print("Checked 2 at tag \(sender.tag) is \(checked[sender.tag])")
}
}
First of all put the selected state into the devices class/struct rather than using an extra array
class Device {
var isSelected = false
...
Second of all don't think in terms of the view think in terms of the model. That means toggle isSelected in the model and reload the row. The benefit is that the view is manipulated reliably only in cellForRow.
For example
#objc func addButtonTapped(_ sender: UIButton) {
let indexPath = IndexPath(row: sender.tag, section: 0)
devices[indexPath.row].isSelected.toggle()
self.tableView.reloadRows(at: [indexPath], with: .none)
if devices[indexPath.row].isSelected && selectedDeviceView.isHidden {
UIView.animate(withDuration: 2.5, delay: 0.7, options: .curveEaseInOut, animations: {
self.tableViewHeightConstraint.constant = self.tableViewHeightConstraint.constant - self.selectedDeviceViewTopConstraint.constant - self.selectedDeviceView.frame.height
self.selectedDeviceViewTopConstraint.constant = 0
self.selectedDeviceView.isHidden = false
}, completion: nil)
}
}
And in cellForRow change
cell.isSelected = scannedDevice.isSelected

My scrolling, while smooth usually, is jerky sometimes

The following is my code. I read using NSDateFormatters were expensive, but I'm not sure if that's what's eventually causing the problem.
Here's my code.
func tableViewOld(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> UITableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
if cell.backgroundView == nil {
cell.backgroundView = UIImageView(frame: cell.contentView.bounds)
cell.backgroundView?.contentMode = UIViewContentMode.ScaleToFill
cell.backgroundView?.clipsToBounds = true
cell.contentView.backgroundColor = UIColor.clearColor()
}
let backgroundImageView = cell.backgroundView as! UIImageView
backgroundImageView.image = UIImage(named: "nobg")
var image : UIImage = UIImage(named:"goodbg")!
cell.nopebutton.tag = indexPath.row
cell.nicebutton.tag = indexPath.row
cell.messageButton.tag = indexPath.row
cell.mText.text = object.valueForKey("text") as? String
let count = object.valueForKey("replies") as! Int
cell.replies.text = "\(count)"
cell.replies.textColor = UIColor.whiteColor()
let point = object["location"] as! PFGeoPoint
let location = CLLocation(latitude: point.latitude, longitude: point.longitude)
let currentLocation = CLLocation(latitude: currLocation!.latitude, longitude: currLocation!.longitude)
let distance = currentLocation.distanceFromLocation(location)
if distance < 50 {
// TODO: Fill
cell.locationButton.text = "Nearby"
} else {
let distanceFormatter = MKDistanceFormatter()
distanceFormatter.unitStyle = MKDistanceFormatterUnitStyle.Abbreviated
cell.locationButton.text = distanceFormatter.stringFromDistance(distance) + " away"
}
cell.layoutMargins = UIEdgeInsetsZero
let score = object.valueForKey("count") as! Int
cell.count.text = "\(score)"
if cell.count.text?.toInt() == 0
{
cell.messages.imageView?.image = UIImage(named:"0")
cell.chatbubble.image = UIImage(named:"ch")
cell.bg.image = UIImage(named: "regular")
cell.locationButton.textColor = UIColor.blackColor()
cell.mText.textColor = UIColor(red: 126.0/255, green: 126.0/255, blue: 126.0/255, alpha: 1)
cell.nicebutton!.setImage(UIImage(named:"ups"), forState: UIControlState.Normal)
cell.nopebutton!.setImage(UIImage(named:"downs"), forState: UIControlState.Normal)
cell.count.textColor = UIColor.whiteColor()
cell.time.textColor = UIColor(red: 52.0/255, green: 152.0/255, blue: 219.0/255, alpha: 1)
}
if cell.count.text?.toInt() > 0
{
cell.messages.imageView?.image = UIImage(named:"1")
cell.chatbubble.image = UIImage(named:"chg")
cell.bg.image = UIImage(named: "gtrl")
cell.time.textColor = UIColor(red: 42.0/255, green: 204.0/255, blue: 113.0/255, alpha: 1)
cell.locationButton.textColor = UIColor.blackColor()
cell.mText.textColor = UIColor(red: 42.0/255, green: 204.0/255, blue: 113.0/255, alpha: 1)
cell.count.textColor = UIColor.whiteColor()
}
if cell.count.text?.toInt() < 0
{
cell.messages.imageView?.image = UIImage(named:"-1")
cell.bg.image = UIImage(named: "ntrl")
cell.chatbubble.image = UIImage(named:"chr")
cell.locationButton.textColor = UIColor.blackColor()
cell.time.textColor = UIColor(red: 231.0/255, green: 76.0/255, blue: 50.0/255, alpha: 1)
cell.mText.textColor = UIColor(red: 231.0/255, green: 76.0/255, blue: 50.0/255, alpha: 1)
cell.count.textColor = UIColor.whiteColor()
}
if cell.count.text?.toInt() >= 100
{
cell.messages.imageView?.image = UIImage(named:"100")
cell.chatbubble.image = UIImage(named:"chb")
cell.locationButton.textColor = UIColor.blackColor()
cell.time.textColor = UIColor(red: 249.0/255, green: 194.0/255, blue: 65.0/255, alpha: 1)
cell.mText.textColor = UIColor(red: 249.0/255, green: 194.0/255, blue: 65.0/255, alpha: 1)
cell.bg.image = UIImage(named: "neutral")
cell.count.textColor = UIColor.whiteColor()
}
if let dict : NSDictionary = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") as? NSDictionary {
cell.nicebutton.enabled = true
cell.nopebutton.enabled = true
if let nice = dict[object.objectId] as? Bool{
if nice {
cell.nicebutton.enabled = false
}
else {
cell.nopebutton.enabled = false
}
}
}
if let user = PFUser.currentUser() {
user["createdBy"] = user.username
//user.saveInBackground()
}
let dateUpdated = object.createdAt as NSDate
let dateFormat = NSDateFormatter()
dateFormat.dateFormat = "h:mm a"
cell.time.text = (NSString(format: "%#", dateFormat.stringFromDate(dateUpdated)) as String) as String
let replycnt = object.objectForKey("replies") as! Int
if cell.count.text == "\(-10)"
{
object.deleteInBackground()
}
return cell
}
and I'm utilizing this extension.
extension NSDate
{
func hour() -> Int
{
//Get Hour
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour, fromDate: self)
let hour = components.hour
//Return Hour
return hour
}
func minute() -> Int
{
//Get Minute
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitMinute, fromDate: self)
let minute = components.minute
//Return Minute
return minute
}
func toShortTimeString() -> String
{
//Get Short Time String
let formatter = NSDateFormatter()
formatter.timeStyle = .ShortStyle
let timeString = formatter.stringFromDate(self)
//Return Short Time String
return timeString
}
}
Is there a way I can optimize this? Again this isn't constantly laggy, it only happens sometimes, but in general it seems to be fine. I'd like to to ALWAYS be fine. Again I feel as though the NSDateFormatter might be the problem, but I'm not quite sure.
You're doing a hell of a lot in the cellForRow method. As a comparison my cellForRow method consists of around 5 lines of code. You should look at creating a custom cell class that removes a lot of that code. With a lot of code it just makes it harder to work out what the cause of problems is.
Each section of that code configures textfields could be a new function. Just, aim for like 10 lines of code per function. If you have more, move stuff into a new function (that makes sense).
What might be causing the issue is creating the NSDateFormatter every time you use the toShortTimeString method.
In fact, I've just seen that you are creating another NSDateFormatter yourself. Creating NSDateFormatter is an expensive thing to do. You should create one as a property of the TableViewController and use that over and over instead of creating it again and again.
That seems like it could be the issue but your function is too big to read through it all. Work on fixing that too.
Number of lines needed in the function... 3.
1 to dequeue the cell.
1 to call a function to configure the cell
1 to return the cell