Swift Xcode TableViewCell's Not Loading First Time - ios

I have a Button which Segues to my TableViewController and when I click the button for the first time, the TableView Doesn't Load but when I go back and click again, my Data Loads.
I tried to set the breakpoints but the tableview functions don't load? Any reason for this?
EDIT:
This is my Code For The TableView, if any other code is required tell me.
class ServicesDisplay: UITableViewController {
#IBOutlet var MainTitle: UILabel!
#IBOutlet var image: UIImageView!
let db = Firestore.firestore()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
performSegue(withIdentifier: "seque", sender: self)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 260
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let jsonFbPic = (jsonFile["SecondScreen"])
let test = ((jsonFbPic["Services Image"]))
let count = ((test["Image\(myIndex)"]))
if count.count == 0 {
return serviceTextArray.count
} else {
return count.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomServicesCell
cell.serviceText?.text = serviceTextArray[indexPath.row]
//Variables
let Json = jsonFile["SecondScreen"]
let MainTitleJson = Json["Text"]
let MainTitleSize = CGFloat(Int("\(MainTitleJson["Size"])")!)
//Main Title:
cell.serviceText.font = UIFont(name: "\(MainTitleJson["Font"])", size: MainTitleSize)
cell.serviceText.textColor = hexStringToUIColor(hex: "\(MainTitleJson["Color"])")
cell.serviceImage?.loadImagesFromCacheWithUrlString(myIndex: indexPath.row, labelName: serviceTextArray[indexPath.row], CellImage: cell.serviceImage)
cell.selectionStyle = .none
return cell
}
public func hexStringToUIColor(hex: String) -> UIColor {
var cString: String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
var rgbValue: UInt64 = 0
if cString.hasPrefix("#") {
cString.remove(at: cString.startIndex)
} else if cString.count != 6 {
return UIColor.black
}
Scanner(string: cString).scanHexInt64(&rgbValue)
return UIColor(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, blue: CGFloat((rgbValue & 0x0000FF)) / 255.0, alpha: CGFloat(1.0))
}
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
}
override func viewDidAppear(_ animated: Bool) {
}
// MARK: - Table view data source
}

Sorry for posting it as an answer but I am also new to stackOverFlow. It Is happening because you are performing segue before the data is fetched from the server. Perform segue as a completion after data fetch is completed. Please let me know if that was a case!

Related

Im populating a PickerView from Core data and getting the error Index Out Of Range Swift 5

I am very new to swift and Im trying to understand populating UIPickerView with CoreData. After following a video on doing this with UITableView I have implemented the same code for a UIPickerView. The code is working fine until I delete everything from CoreData then it crashes with the error index out of range.
I know the line of code where it is crashing but I do know how to fix it. I have read many questions here regarding Index out Of range but I cant see anything the same.
Here is the code, the table view code is from a video and I do understand 80% of it.
The crash line of code is right at the bottom
import UIKit
import CoreData
// Global Variables and Constants
let appDelegate = UIApplication.shared.delegate as? AppDelegate
class ViewController: UIViewController {
// Outlets
#IBOutlet weak var tv: UITableView!
#IBOutlet weak var pickerView: UIPickerView!
// Varables
var taskArray = [Task]()
// Constants
let cellid = "CellId"
func randomNumber(num: Int) -> Int{
return Int(arc4random_uniform(UInt32(num)))
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callDelegates()
}
override func viewWillAppear(_ animated: Bool) {
fetchyData()
tv.reloadData()
pickerView.reloadAllComponents()
}
func fetchyData(){
fetchData { (done) in
if done {
if taskArray.count > 0 {
tv.isHidden = false
pickerView.isHidden = false
} else {
tv.isHidden = true
pickerView.isHidden = true
}
}
}
}
func callDelegates(){
tv.delegate = self
tv.dataSource = self
tv.isHidden = true
pickerView.dataSource = self
pickerView.delegate = self
pickerView.isHidden = self
}
#IBAction func btnPressedButton(_ sender: Any) {
//textLbl.text = "\(items)"
pickerView.selectRow(randomNumber(num: 1000), inComponent: 0, animated: true)
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return taskArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellid, for: indexPath) as! TableViewCell
let task = taskArray[indexPath.row]
cell.taskLbl.text = task.taskDescription
if task.taskStatus == true {
cell.backgroundColor = #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)
cell.taskLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
self.deleteData(indexPath: indexPath)
self.fetchyData()
tableView.deleteRows(at: [indexPath], with: .automatic)
}
let taskStatusAction = UITableViewRowAction(style: .normal, title: "Completed") { (action, indexPath) in
self.updateTaskStatus(indexPath: indexPath)
self.fetchyData()
tableView.reloadRows(at: [indexPath], with: .automatic)
}
taskStatusAction.backgroundColor = #colorLiteral(red: 0.7254902124, green: 0.4784313738, blue: 0.09803921729, alpha: 1)
deleteAction.backgroundColor = #colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1)
return [deleteAction, taskStatusAction]
}
}
extension ViewController {
func fetchData(completion: (_ complete: Bool) -> ()) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Task")
do {
taskArray = try managedContext.fetch(request) as! [Task]
print("Data fetched, no issues")
completion(true)
} catch {
print("Unable to fetch data: ", error.localizedDescription)
completion(false)
}
}
func deleteData(indexPath: IndexPath) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
managedContext.delete(taskArray[indexPath.row])
do {
try managedContext.save()
print("Data Deleted")
} catch {
print("Failed to delete data: ", error.localizedDescription)
}
}
func updateTaskStatus(indexPath: IndexPath) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
let task = taskArray[indexPath.row]
if task.taskStatus == true {
task.taskStatus = false
} else {
task.taskStatus = true
}
do {
try managedContext.save()
print("Data updated")
} catch {
print("Failed to update data: ", error.localizedDescription)
}
}
}
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
self.fetchyData()
return taskArray.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
self.fetchyData()
return taskArray[row].taskDescription. //THE ERROR IS ON THIS LINE . Index Out OF Range//
}
}
Check before accessing an element in array if you are getting outOfIndex crash
An excellent way in Swift:
let isIndexValid = taskArray.indices.contains(row)
if isIndexValid {
return taskArray[row].taskDescription
} else {
return "default text"
}

want to display image into tableview cell from an api with only image name

I have an API in which only image_name is given. How do I load an image into a UITableViewCell. I am using Alamofire and SwiftyJSON for it. I am getting hotal_originalname and hotal_address but no image. I have tried but not getting it.
The Code I have tried so far:
hotelModel struct:
struct hotelModel {
var hotal_originalname:String = ""
var hotal_image:String = ""
var hotal_address:String = ""
init(json:JSON) {
hotal_originalname = json["hotal_originalname"].stringValue
hotal_image = json["hotal_image"].stringValue
hotal_address = json["hotal_address"].stringValue
}
}
Code with Alamofire code:
class ListViewController: UIViewController{
let BASE_URL = "https://socialinfotech.in/development/ExcelReport/api/v1/hotel"
let headers: HTTPHeaders = [
"X-Authorization": "2933c869ebe0a3e42a068ec50e305db5",
"Content-Type": "application/x-www-form-urlencoded"
]
var arrData = [hotelModel]()
// MARK: IBOutlets
#IBOutlet weak var listViewTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//set gradient to navigation bar
SHNDNavigationBarGradient(firstColor: #colorLiteral(red: 0.3450980392, green: 0.737254902, blue: 0.9568627451, alpha: 1), secondColor: #colorLiteral(red: 0.262745098, green: 0.6078431373, blue: 0.7921568627, alpha: 1))
jsonParsing()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
func jsonParsing() {
Alamofire.request(BASE_URL, method: .get, headers: headers).responseJSON { (response)-> Void in
debugPrint(response)
if(response.result.value) != nil {
let json = JSON(response.result.value!)
let results = json["Result"]
for arr in results.arrayValue {
self.arrData.append(hotelModel(json: arr))
print(self.arrData)
}
DispatchQueue.main.async {
self.listViewTable.reloadData()
}
}
}
}
//MARK: IBActions
#IBAction func logoutBtnTapped(_ sender: UIBarButtonItem) {
UserDefaults.standard.set(false, forKey: "ISUSERLOGGEDIN")
self.navigationController?.popToRootViewController(animated: true)
}
}
extension ListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell", for: indexPath) as! ListCell
let imgUrl = "http://socialinfotech.in/development/ExcelReport/uploads/original/"
let url = imgUrl + "uploads-35766-1557402138-20190509-114218am.jpg"
cell.hotelImage.kf.setImage(with: URL(string: url))
cell.hotelName.text = arrData[indexPath.row].hotal_originalname
cell.hotelAddress.text = arrData[indexPath.row].hotal_address
//
// Alamofire.request(url).responseImage { (response) in
// if let image = response.result.value {
// cell.hotelImage.image = image
// }
// }
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let chartVC = self.storyboard?.instantiateViewController(withIdentifier: "ChartViewController") as! ChartViewController
self.navigationController?.isNavigationBarHidden = false
self.navigationController?.pushViewController(chartVC, animated:true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
}
You are using static image url.
Replace this line
let imgUrl = "http://socialinfotech.in/development/ExcelReport/uploads/original/"
let url = imgUrl + "uploads-35766-1557402138-20190509-114218am.jpg"
with
let imgUrl = "http://socialinfotech.in/development/ExcelReport/uploads/original/"
let url = imgUrl + arrData[indexPath.row].hotal_image
Hope it is helpful

blocking phone number in call kit

I'm trying to using CallKit to add a feature to my app to add some phone numbers to blacklist!
the code below is my whole view!!
class BlacklistViewController: UIViewController ,UITableViewDataSource, UITableViewDelegate {
var phoneNumbersArrCoreData = [BlockedPhoneNumbers]()
var listPhoneNumbers:[CXCallDirectoryPhoneNumber] = []
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var BtnAddO: UIButton!
#IBOutlet weak var EntPhonenumber: UITextField!
#IBAction func BtnAddA(_ sender: Any) {
if !(EntPhonenumber.text?.isEmpty)!
{
let blackedPhonenumbers_CoreData = BlockedPhoneNumbers(context: PersistanceService.context)
blackedPhonenumbers_CoreData.phoneNumber = Int64.init(EntPhonenumber.text!)!
PersistanceService.saveContext()
getCoreData()
TableView.reloadData()
}
}
var coreData = [BlockedPhoneNumbers]()
func getCoreData()
{
listPhoneNumbers.removeAll()
let fetchRequest : NSFetchRequest<BlockedPhoneNumbers> = BlockedPhoneNumbers.fetchRequest()
do
{
let FetchedResultFromDB = try PersistanceService.context.fetch(fetchRequest)
coreData = FetchedResultFromDB
print("============\n===========\n")
if coreData.count > 0
{
for i in 0..<coreData.count
{
listPhoneNumbers.append(coreData[i].phoneNumber)
}
}
print("============\n===========\n")
}
catch{
print("gettin blocked number from db got error")
}
}
override func viewDidLoad() {
BtnAddO.layer.cornerRadius = 5
BtnAddO.layer.borderColor = UIColor.white.cgColor
BtnAddO.layer.borderWidth = 0.8
EntPhonenumber.attributedPlaceholder = NSAttributedString(string: "Enter a phone number to block",attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightText])
getCoreData()
super.viewDidLoad()
view.backgroundColor = UIColor.init(red: 25/255, green: 28/255, blue: 46/255, alpha: 1)
TableView.delegate = self
TableView.dataSource = self
}
func beginRequest(with context: CXCallDirectoryExtensionContext) {
getCoreData()
let blockedPhoneNumbers: [CXCallDirectoryPhoneNumber] = listPhoneNumbers
for phoneNumber in blockedPhoneNumbers.sorted(by: <) {
context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)
}
context.completeRequest()
}
//MARK: - TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listPhoneNumbers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BlackListCell") as? BlackListTableViewCell
cell?.ContactImg.layer.masksToBounds = true
cell?.mainView.layer.cornerRadius = 10
cell?.mainView.backgroundColor = UIColor(red: 42/255, green: 48/255, blue: 66/255, alpha: 1)
cell?.ContactImg.layer.cornerRadius = 5
cell?.ContactImg.image = UIImage(named: "Blocked")
cell?.unBlock.imageView?.image = nil
cell?.unBlock.setTitle("UNBLOCK", for: UIControl.State.normal)
cell?.unBlock.layer.cornerRadius = (cell?.unBlock.frame.size.height)!/2
cell?.SetUnblockBtn {
I get the error here,below
let context:NSManagedObjectContext = PersistanceService.context
context.delete(self.phoneNumbersArrCoreData[indexPath.row] as NSManagedObject)
self.phoneNumbersArrCoreData.remove(at: indexPath.row)
print("data deleted!!!")
}
cell?.phoneNumber.text = String(listPhoneNumbers[indexPath.row])
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 85
}
}
to explain the code, I save each number that user will enter in a core data(entityName: BlockedPhoneNumbers). I'm not sure even if this is the right way to save numbers that they need to be blocked or not!!
when the user presses the button I save the number and it works fine( but I'm not sure if this is the right way or not!!).
and in getCoreData I get the core data and show them in a table view. which shows that core data works fine! but when user wanna unblock the contact and presses the button in CELL of the table view, I get an error and app crash and it says:
Thread 1: Fatal error: Index out of range
my problems are:
why do I get this error?
2.as I can not find any tutorial for callKit I believe that I'm doing this job wrong.
could anyone help me with this?
You have too many arrays:
listPhoneNumbers which contains your integer numbers
coreData which contains your Core Data items
phoneNumbersArrCoreData which could contain your Core Data items, but you don't add anything to it.
As a result, phoneNumbersArrCoreData is empty. When you try and remove an object from the empty array you get an array bounds exception.
You should eliminate two of the three arrays.
class BlacklistViewController: UIViewController ,UITableViewDataSource, UITableViewDelegate {
var blockedNumbers = [BlockedPhoneNumbers]()
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var BtnAddO: UIButton!
#IBOutlet weak var EntPhonenumber: UITextField!
#IBAction func BtnAddA(_ sender: Any) {
if !(EntPhonenumber.text?.isEmpty)!
{
let blackedPhonenumbers_CoreData = BlockedPhoneNumbers(context: PersistanceService.context)
blackedPhonenumbers_CoreData.phoneNumber = Int64.init(EntPhonenumber.text!)!
PersistanceService.saveContext()
getCoreData()
TableView.reloadData()
}
}
func getCoreData()
{
let fetchRequest : NSFetchRequest<BlockedPhoneNumbers> = BlockedPhoneNumbers.fetchRequest()
do
{
let FetchedResultFromDB = try PersistanceService.context.fetch(fetchRequest)
blockedNumbers = FetchedResultFromDB
print("============\n===========\n")
}
catch{
print("gettin blocked number from db got error")
}
}
override func viewDidLoad() {
BtnAddO.layer.cornerRadius = 5
BtnAddO.layer.borderColor = UIColor.white.cgColor
BtnAddO.layer.borderWidth = 0.8
EntPhonenumber.attributedPlaceholder = NSAttributedString(string: "Enter a phone number to block",attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightText])
getCoreData()
super.viewDidLoad()
view.backgroundColor = UIColor.init(red: 25/255, green: 28/255, blue: 46/255, alpha: 1)
TableView.delegate = self
TableView.dataSource = self
}
//MARK: - TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return blockedNumbers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BlackListCell") as? BlackListTableViewCell
cell?.ContactImg.layer.masksToBounds = true
cell?.mainView.layer.cornerRadius = 10
cell?.mainView.backgroundColor = UIColor(red: 42/255, green: 48/255, blue: 66/255, alpha: 1)
cell?.ContactImg.layer.cornerRadius = 5
cell?.ContactImg.image = UIImage(named: "Blocked")
cell?.unBlock.imageView?.image = nil
cell?.unBlock.setTitle("UNBLOCK", for: UIControl.State.normal)
cell?.unBlock.layer.cornerRadius = (cell?.unBlock.frame.size.height)!/2
cell?.SetUnblockBtn {
let context:NSManagedObjectContext = PersistanceService.context
context.delete(self.blockedNumbers[indexPath.row] as NSManagedObject)
self.phoneNumbersArrCoreData.remove(at: indexPath.row)
print("data deleted!!!")
}
cell?.phoneNumber.text = blockedNumbers[indexPath.row].phoneNumber
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 85
}
}
The code to actually load data into the Call Kit block list needs to go into a CallKit extension in your app. You will need to use an application group to share the Core Data store with the extension.

Get section header cell in gesture method

I am working on a 'UITableView' with different section headers. Section header contains a tab gesture recognization to expand and collapse the section.
In the section header view, I have used an image for the accessory icon to show the user the section is expanded or collapsed.
My concern is when I tap section header then control goes to the gesture method. In that method how should I get the header cell to update the image accordingly?
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
if self.useSearchDefinitions {
if let ret = tableView.dequeueReusableCell(withIdentifier: INBOX_HEADER_CELL_IDENTIFIER) as? InboxHeaderCell {
ret.contentView.backgroundColor = UIColor(red: 236 / 255.0, green: 236 / 255.0, blue: 236 / 255.0, alpha: 1.0)
ret.contentView.tag = section
ret.lblHeaderTitle?.textColor = UIColor(red: 110 / 255.0, green: 110 / 255.0, blue: 110 / 255.0, alpha: 1.0)
ret.lblHeaderTitle?.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)
ret.lblHeaderTitle?.text = presenter.sectionTitle(section)
ret.accessoryImage.image = UIImage(named: "inbox-expand.png")
// Set tap gesture
let headerViewTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.headerViewGestureHandler))
headerViewTapRecognizer.delegate = self
headerViewTapRecognizer.numberOfTouchesRequired = 1
headerViewTapRecognizer.numberOfTapsRequired = 1
ret.contentView.addGestureRecognizer(headerViewTapRecognizer)
return ret.contentView
}
}
return nil
}
and this is to get the gesture
func headerViewGestureHandler(_ sender: UIGestureRecognizer)
{
tableView.beginUpdates()
if let tag = sender.view?.tag {
let section = Int(tag)
let shouldCollapse: Bool = !collapsedSections.contains((section))
let numOfRows = Int(presenter.numberOfRows(tag))
}
}
how should I get the particular clicked section header cell in this method so I can update the image accordingly?
Thanks in advance.
I would recommend:
put the Gesture code inside your section header
using a "call back" closure for passing the tap back to the view controller
Here is a simple example (assumes you have a View Controller with a Table View, hooked up via IBOutlet):
class SimpleSectionHeaderView: UITableViewHeaderFooterView, UIGestureRecognizerDelegate {
// typical UILabel
var lblHeaderTitle: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
// this is our "call back" closure
var headerTapCallback: (() -> ())?
func headerViewGestureHandler(_ sender: UIGestureRecognizer) {
// just for debugging, so we know the tap was triggered
print("tapped!!!")
// "call back" to the view controller
headerTapCallback?()
}
func commonInit() {
// set our backgroundColor
contentView.backgroundColor = .cyan
// add a label and set its constraints
self.addSubview(lblHeaderTitle)
lblHeaderTitle.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8.0).isActive = true
lblHeaderTitle.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true
// Set tap gesture
let headerViewTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.headerViewGestureHandler))
headerViewTapRecognizer.delegate = self
headerViewTapRecognizer.numberOfTouchesRequired = 1
headerViewTapRecognizer.numberOfTapsRequired = 1
// add it to self
self.addGestureRecognizer(headerViewTapRecognizer)
}
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
}
class TableWithSectionHeadersViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var theTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// standard cell registration
theTableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseIdentifier")
theTableView.register(SimpleSectionHeaderView.self, forHeaderFooterViewReuseIdentifier: "simpleHeaderView")
// make sure these are set (in case we forgot in storyboard)
theTableView.delegate = self
theTableView.dataSource = self
}
func handleHeaderTap(_ section: Int) -> Void {
// do whatever we want based on which section header was tapped
print("View Controller received a \"tapped\" in header for section:", section)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: "simpleHeaderView") as! SimpleSectionHeaderView
// set the view's label text
v.lblHeaderTitle.text = "Section \(section)"
// set the view's "call back" closure
v.headerTapCallback = {
_ in
self.handleHeaderTap(section)
}
return v
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60;
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
// Configure the cell...
cell.textLabel?.text = "\(indexPath)"
return cell
}
}
This also eliminates any need to set any .tag properties (which is generally a bad idea, for a number of reasons).

UITableView only updating on scroll up, not down

I have a UITableView that updates when I scroll up, but it does not update when I scroll down. Furthermore, when it does update it occasionally seems to "skip" a cell and update the next one.
There are 6 total cells that should populate
I've created the UITableView in the storyboard, set my constraints for both the hashLabel and the creditLabel in storyboard
Here is the image of the initial TableView:
And upon scrolling up, when updated properly:
...and when scrolling up "misses" a cell:
and of course, the class:
class HashtagController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var model:ModelData!
var currentCell: UITableViewCell!
#IBOutlet var hashtagTableView: UITableView!
let basicCellIdentifier = "CustomCells"
override func viewDidLoad() {
super.viewDidLoad()
model = (self.tabBarController as CaptionTabBarController).model
hashtagTableView.delegate = self
hashtagTableView.dataSource = self
self.navigationController?.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "CherrySwash-Regular", size: 25)!, NSForegroundColorAttributeName: UIColor(red:27.0/255, green: 145.0/255, blue: 114.0/255, alpha: 1.0)]
configureTableView()
hashtagTableView.reloadData()
}
func configureTableView() {
hashtagTableView.rowHeight = UITableViewAutomaticDimension
hashtagTableView.estimatedRowHeight = 160.0
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//deselectAllRows()
hashtagTableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
hashtagTableView.reloadData()
}
func deselectAllRows() {
if let selectedRows = hashtagTableView.indexPathsForSelectedRows() as? [NSIndexPath] {
for indexPath in selectedRows {
hashtagTableView.deselectRowAtIndexPath(indexPath, animated: false)
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.quoteItems.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return customCellAtIndexPath(indexPath)
}
func customCellAtIndexPath(indexPath:NSIndexPath) -> CustomCells {
var cell = hashtagTableView.dequeueReusableCellWithIdentifier(basicCellIdentifier) as CustomCells
setTitleForCell(cell, indexPath: indexPath)
setSubtitleForCell(cell, indexPath: indexPath)
return cell
}
func setTitleForCell(cell:CustomCells, indexPath:NSIndexPath) {
let item = Array(Array(model.quoteItems.values)[indexPath.row])[0] as? String
cell.hashLabel.text = item
}
func setSubtitleForCell(cell:CustomCells, indexPath:NSIndexPath) {
let item = Array(model.quoteItems.keys)[indexPath.row]
cell.creditLabel.text = item
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
/*currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
var currentLabel = currentCell.textLabel?.text
var currentAuthor = currentCell.detailTextLabel?.text
model.quote = currentLabel!
model.author = currentAuthor!*/
}
}
class CustomCells: UITableViewCell {
#IBOutlet var hashLabel: UILabel!
#IBOutlet var creditLabel: UILabel!
}
As it turns out, the issue had to do with my estimatedRowHeight. In this case the row height was too large and it was effecting the way the table cells were being constructed.
So in the end I changed hashtagTableView.estimatedRowHeight = 160.0 to hashtagTableView.estimatedRowHeight = 80.0 and everything worked just fine.

Resources