I'm trying to set tableHeaderView in numberOfRowsInSection. But I'm getting EXC_BAD_ACCESS with no message in the output console.
Below is my numberOfRowsInSection function.
// number of rows in table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//SECTION 1
if self.titles.count == 0 {
self.noBookmarkView.alpha = 1.0
}
else {
self.noBookmarkView.alpha = 0.0
}
//=====================================
//SECTION 2
if self.idsb.count != self.ids.count {
self.bookmarkTableView.tableHeaderView = self.filteredView
}
else {
self.bookmarkTableView.tableHeaderView = nil
}
//=====================================
return self.titles.count
}
And below is my viewDidLoad where I initialize filteredView
#IBOutlet weak var noBookmarkView: UIView!
var filteredView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
filteredView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: bookmarkTableView.frame.width, height: 25))
filteredView.backgroundColor = UIColor.init(red: 0.4, green: 0.4, blue: 0.71, alpha: 1.0)
let label: UILabel = UILabel.init(frame: filteredView.frame)
label.text = "Filtered"
label.font = UIFont.init(name: "System", size: 14.0)
label.adjustsFontSizeToFitWidth = true
filteredView.addSubview(label)
}
So before I added filteredView it worked perfectly with the noBookmarkView.
Now it has the error EXC_BAD_ACCESS on self.noBookmarkView.alpha = 0.0. If I comment out SECTION 2 it works without errors. If I comment out SECTION 1 it then has EXC_BAD_ACCESS on line self.bookmarkTableView.tableHeaderView = nil.
I don't understand why it would fail on self.noBookmarkView.alpha = 0.0 when it seems like SECTION 2 is what is causing the problem.
How can I fix this?
You should provide header via the dataSource of the UITableView:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return self.filteredView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 25
}
Related
I have a search controller added to navigationController.searchController. When the screen initially loads there is a black space above the navigation bar. Only when I tap on the search bar this space correctly shows white. When I tap off the search bar, this area shows black again.
import UIKit
import Foundation
import InstantSearch
class AlgoliaViewController: UIViewController, UISearchBarDelegate {
let userHitsInteractor: HitsInteractor<User> = .init(infiniteScrolling: .off, showItemsOnEmptyQuery: false)
let businessHitsInteractor: HitsInteractor<Business> = .init(infiniteScrolling: .off, showItemsOnEmptyQuery: false)
let multiSearch = MultiIndexSearcher(appID: APP_ID, apiKey: APP_KEY, indexNames: ["dev_USERS","dev_BUSINESS"])
lazy var multiConnector: MultiIndexSearchConnector = .init(searcher: multiSearch, indexModules: [
.init(indexName: "dev_USERS",
hitsInteractor: userHitsInteractor),
.init(indexName: "dev_BUSINESS",
hitsInteractor: businessHitsInteractor)
], searchController: searchController, hitsController: hitsTableViewController)
lazy var searchController: UISearchController = .init(searchResultsController: hitsTableViewController)
let hitsTableViewController = MultiIndexController()
let statsInteractor: StatsInteractor = .init()
override func viewDidLoad() {
super.viewDidLoad()
multiConnector.connect()
multiSearch.search()
statsInteractor.connectController(self)
setupUI()
}
func setupUI() {
view.backgroundColor = .white
navigationItem.searchController = searchController
navigationController?.navigationBar.backgroundColor = .white
// navigationItem.titleView = searchController.searchBar
navigationController?.navigationBar.backgroundColor = .white
navigationController?.navigationBar.isTranslucent = false
navigationController?.hidesBarsOnSwipe = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.showsSearchResultsController = true
searchController.automaticallyShowsCancelButton = false
searchController.searchBar.delegate = self
searchController.obscuresBackgroundDuringPresentation = false
hitsTableViewController.view.backgroundColor = .white
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchController.isActive = true
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchController.isActive = false
}
}
extension AlgoliaViewController: StatsTextController {
func setItem(_ item: String?) {
title = item
}
}
class MultiIndexController: UITableViewController, MultiIndexHitsController {
var hitsSource: MultiIndexHitsSource?
let cellID = "cellID"
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(ResultsItemCell.self, forCellReuseIdentifier: cellID)
setupUI()
self.tableView.keyboardDismissMode = .onDrag
}
func setupUI() {
view.backgroundColor = .white
tableView.backgroundColor = .white
tableView.separatorStyle = .none
}
override func numberOfSections(in tableView: UITableView) -> Int {
return (hitsSource?.numberOfSections())!
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (hitsSource?.numberOfHits(inSection: section)) ?? 0
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 50))
let sectionTitle = UILabel(frame: CGRect(x: 0, y: 0, width: headerView.frame.width, height: headerView.frame.height))
Utilities.styleLblFont(sectionTitle, fontName: "Cabin-SemiBold", fontSize: 18, color: .black)
var headertitle = ""
switch section {
case 0:
print("section 0")
headertitle = "People"
case 1:
print("section 1")
headertitle = "Businesses"
default:
break
}
headerView.backgroundColor = .white
sectionTitle.text = headertitle
headerView.addSubview(sectionTitle)
return headerView
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! ResultsItemCell
switch indexPath.section {
case 0:
if let item: User = try? hitsSource?.hit(atIndex: indexPath.row, inSection: indexPath.section) {
cell.nameLbl.text = item.userName
cell.avatar.loadImage(item.profilePhotoUrl)
cell.jobTitleLbl.text = item.userType
}
case 1:
if let business: Business = try? hitsSource?.hit(atIndex: indexPath.row, inSection: indexPath.section) {
cell.nameLbl.text = business.businessName
cell.avatar.loadImage(business.businessAvatarUrl)
cell.jobTitleLbl.text = business.mission
}
default:
break
}
return cell
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 50))
let seeResultsBtn = UIButton(frame: CGRect(x: 0, y: 0, width: footerView.frame.width, height: footerView.frame.height))
var footerTitle = ""
switch section {
case 0:
footerTitle = "See all people"
case 1:
footerTitle = "See all businesses"
default:
footerTitle = "See all results"
}
footerView.addSubview(seeResultsBtn)
seeResultsBtn.translatesAutoresizingMaskIntoConstraints = false
seeResultsBtn.centerYAnchor.constraint(equalTo: footerView.centerYAnchor).isActive = true
seeResultsBtn.centerXAnchor.constraint(equalTo: footerView.centerXAnchor).isActive = true
Utilities.buttonTitle(seeResultsBtn, title: footerTitle, titleColour: .jabiMain, fontName: "Cabin-Medium", fontSize: 16)
footerView.backgroundColor = .white
return footerView
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 50
}
}
Please see the screenshots:
I have a table view that is subclassed and extended, then being set up in the View controller. The problem that I'm having is the delegate method ViewForHeaderInSection isn't being called, while the normal data source methods are being called.
(this is the TableView setup method, is called in ViewDidLoad. The table view is connected to the View Controller with IBOutlet)
func setup() {
self.dataSource = self as UITableViewDataSource
self.delegate = self
let nib = UINib(nibName: "MyTableViewCell", bundle: nil)
self.register(nib, forCellReuseIdentifier: "MyCell")
}
These are the extensions
extension MyTableView: UITableViewDataSource,UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
//print(Genres.total.rawValue)
return Genres.total.rawValue
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let tableSection = Genres(rawValue: section), let articleData = articleDictionary[tableSection] {
// print(articleData.count)
return articleData.count
}
print(0)
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell") as! MyTableViewCell
if let tableSection = Genres(rawValue: indexPath.section), let article = articleDictionary[tableSection]?[indexPath.row]{
cell.cellTitle.text = article.articleTitle
cell.cellImageView.image = article.articleImage
cell.cellEmojiReaction.text = article.articleEmojis
}
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 40.0))
view.backgroundColor = .brown
let label = UILabel(frame: CGRect(x: 16, y: 0, width: tableView.bounds.width, height: 40))
label.textColor = .blue
let tableSection = Genres(rawValue: section)
switch tableSection {
case .breakingNews?:
label.text = "Breaking News"
case .scienceAndTech?:
label.text = "Science and Tech"
case .entertainment?:
label.text = "Entertainment"
case .sports?:
label.text = "Sports"
default:
label.text = "Invalid"
}
print("Function Run")
view.addSubview(label)
print(label.text ?? "Nothing Here")
return view
}
}
Here is the View controller Code:
class ViewController: UIViewController {
#IBOutlet weak var myTableView: MyTableView!
override func viewDidLoad() {
super.viewDidLoad()
myTableView.setup()
}
}
Is there any specific reason why the delegate method isn't being called? Thank you in advance for your time.
For this you have to also implement one more method heightForHeaderInSection along with viewForHeaderInSection method.
If you are using viewForHeaderInSection delegate method then it is compulsory to use heightForHeaderInSection method other wise section header mehtod is not called
Prior to iOS 5.0, table views would automatically resize the heights
of headers to 0 for sections where
tableView(_:viewForHeaderInSection:) returned a nil view. In iOS 5.0
and later, you must return the actual height for each section header
in this method.
Official Link for more description https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614855-tableview
Add in viewDidLoad:
tableView.estimatedSectionHeaderHeight = 80
I’m currently developing a Menu screen in my sprite kit game to show all of the items and i’ve used a tableview to achieve this because it allows me to have a uilabel for the item description.
my uitableview is subclassed as follows:
UITableview Class
import Foundation
import SpriteKit
import UIKit
class GameRoomTableView: UITableView,UITableViewDelegate,UITableViewDataSource {
var items: [String] = []
var descrip: [String] = []
var title: [String] = []
var isFirstViewAlreadyAdded = false
var isSecondViewAlreadyAdded = false
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
self.delegate = self
self.dataSource = self
coreDataItemRetrieveval()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
return items.count
}
func coreDataItemRetrieveval() {
items.removeAll(); descrip.removeAll(); title.removeAll()
items.append("Player1")
descrip.append("Grown on Astrums Home world of Zaharia the forbidden fruit when eaten results in a headstart for the player")
title.append("Athia Fruit")
items.append("Player2")
descrip.append("HHHHHH HHHHHH HHHHHHHHHH HHHHHHH HHHHHHHH HHHHHHHH HHHHHHHHH HHHHHHHHH ")
title.append("AtTTTTTTT")
items.append("Player2")
descrip.append("TESTING ")
title.append("AtTTTTTTT")
items.append("Player2")
descrip.append("TESTING ")
title.append("AtTTTTTTT")
items.append("Player2")
descrip.append("TESTING ")
title.append("AtTTTTTTT")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
tableView.allowsSelection = false
tableView.showsVerticalScrollIndicator = false
tableView.backgroundColor = .clear
tableView.backgroundView = nil
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let CellIdentifier: String = "Cell"
var cell: UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: CellIdentifier)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: nil)
//IMPLEMENT CORE DATA RETRIEVEAL AND SO ON TO MAKE IT BETTER USE APPEND ARRAYS AND SO ON TO GET THIS DONE AND IMPLEMENT QUANTITY LABEL.
cell?.imageView?.image = UIImage(named:(self.items[indexPath.section] + ".png"))
cell?.imageView?.transform = CGAffineTransform(scaleX: 0.5, y: 0.5);
cell?.textLabel?.text = self.descrip[indexPath.section]
cell?.textLabel?.numberOfLines = 0
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.frame = CGRect(x: (cell?.frame.size.width)! / 2.6, y: (cell?.frame.size.height)! / 1.7, width: 150, height: 50)
let textlabel2 = UILabel(frame: CGRect(x: (cell?.frame.size.width)! / 2.6, y: (cell?.frame.size.height)! / 1.4, width: 150, height: 50))
textlabel2.text = self.title[indexPath.section]
textlabel2.numberOfLines = 0
textlabel2.adjustsFontSizeToFitWidth = true
cell?.contentView.addSubview(textlabel2)
}
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200.00
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = UIColor.clear
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor.white
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return " "
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")
}
}
GameScene:
class GameScene: SKScene {
var gameTableView = GameRoomTableView()
private var label : SKLabelNode?
override func didMove(to view: SKView) {
gameTableView.frame = CGRect(x:14,y:100, width: frame.maxX / 1.08, height: frame.maxY) //(scene?.view?.frame.maxY)!)
gameTableView.contentSize = CGSize(width: gameTableView.frame.size.width, height: gameTableView.frame.size.height)
self.scene?.view?.addSubview(gameTableView)
gameTableView.reloadData()
}
}
the only problem I have is when I scroll to the bottom of the tableview It seems that half of the last cell is cut off from being scrolled to and I can’t see it fully the tableview has multiple sections because I wanted gaps between each cell and that was the only way I could achieve It. How do I change the scrolling of the tableview to be longer so I can see all of the cells fully? I have tried looking into other answers on here and I've had no luck fixing it.
Your issue is in the line:
override func didMove(to view: SKView) {
gameTableView.frame = CGRect(x:14,y:100, width: frame.maxX / 1.08, height: frame.maxY)
...
This happened because your gameTableView height is bigger than the scene height:
To solve you can try to decrease the height of your table for example:
gameTableView.frame = CGRect(x:14,y:100, width: frame.maxX / 1.08, height: frame.maxY/2)
i get a response from API like this:
[{
"name":"apple"
"type": "Fruit"
"taste": sweet
}
{
"name":"lemon"
"type": "Fruit"
"taste": "not tasty"
}]
and now i want to set the title of the section as name of UITable view.
for this i have called this in my view controller as:
var modelclass = [FruitsModelclass]()
override func viewDidLoad()
{
self.loaddata()
}
func loaddata()
{
//here i have called the API and sucessfully get the response in data and assign as
self.modelclass = data
self.tableView.reloadData()
}
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
let cell = tableView!.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath!) as FruitCell
let model = self.Modeldata[indexpath.row]
cell.textlabel.text = model.name
return cell
}
this is how i set the name to cell.How can i set this to my headerSection..??there are alot of json objects in my Api its not fixed one. Here i have presented only two in can anyone help me out..??
If you just want to add title...
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "SOME TEXT" //return your text here, may be
}
if you want control over header view then something like this
public func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat{
return 50 //height you want of section
}
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?{
let vw = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50))
//view for header, you can also use view from nib, but thats another matter
vw.backgroundColor = UIColor.white
let label = UILabel(frame: CGRect(x: 10, y: 0, width: tableView.frame.size.width-10, height: 50))
//add label or buttons or what ever u want to view....
label.text = “SOME TEXT“
vw.addSubview(label)
return vw
}
And as a side note numberOfSections is imp to show headers
I'm trying to make section headers with autolayout.
A simple header with a title and a counter
class ProfilePeopleListHeaderViewCell: UIView {
let titleLeftOffset = 12
let counterRightOffset = 5
let counterWidth = 50
var title = "title" {
didSet {
titleLabel.text = title
}
}
var numberOfPeople = 0 {
didSet {
peopleCounter.text = "\(numberOfPeople)"
}
}
let titleLabel = UILabel()
let peopleCounter = UILabel()
convenience init(title: String, numberOfPeople:Int) {
self.init()
self.title = title
self.numberOfPeople = numberOfPeople
backgroundColor = UIColor.greenColor()
titleLabel.textColor = Constants.Colors.ThemeGreen
titleLabel.textAlignment = .Left
if #available(iOS 8.2, *) {
titleLabel.font = Constants.Fonts.Profile.PeopleListHeaderFont
peopleCounter.font = Constants.Fonts.Profile.PeopleListHeaderFont
} else {
titleLabel.font = UIFont.systemFontOfSize(14)
peopleCounter.font = UIFont.systemFontOfSize(14)
}
peopleCounter.textAlignment = .Right
peopleCounter.textColor = Constants.Colors.ThemeDarkGray
addSubview(titleLabel)
addSubview(peopleCounter)
self.titleLabel.snp_makeConstraints { (make) -> Void in
make.centerY.equalTo(self)
make.height.equalTo(self)
make.width.equalTo(peopleCounter).multipliedBy(3)
make.left.equalTo(self).offset(titleLeftOffset)
}
self.peopleCounter.snp_makeConstraints { (make) -> Void in
make.centerY.equalTo(self)
make.height.equalTo(self)
make.width.equalTo(counterWidth)
make.left.equalTo(titleLabel.snp_right)
make.right.equalTo(self).offset(counterRightOffset)
}
}
}
The code to retrieve the header is:
let mutualFriendsSectionView = ProfilePeopleListHeaderViewCell(title: Strings.Title.MutualFriends, numberOfPeople: 0)
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 1 {
//mutualFriendsSectionView.layoutSubviews()
return mutualFriendsSectionView
}
}
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
I get a green background in the section header.
But I don't see any label...
Try this out for UITableView Section Header.
Programatically create headerview
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRectMake(0, 0, tblView.bounds.size.width, 50))
let lblHeader = UILabel.init(frame: CGRectMake(15, 13, tableView.bounds.size.width - 10, 24))
if section == 0 {
lblHeader.text = "Image Settings"
}
else if section == 1 {
lblHeader.text = "Personal Settings"
}
else {
lblHeader.text = "Other Settings"
}
lblHeader.font = UIFont (name: "OpenSans-Semibold", size: 18)
lblHeader.textColor = UIColor.blackColor()
headerView.addSubview(lblHeader)
headerView.backgroundColor = UIColor(colorLiteralRed: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 1.0)
return headerView
}
Height for HeaderView
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
Check if a tableView delegate is connected
Actually it's working.
my mistake was to believe that didSet{} was also called within the class -> it's not the case.
When I was setting the title in the init() it was not setting the label text.
try instantiating your headerView inside viewForHeader method
Edit your code as below
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let mutualFriendsSectionView = ProfilePeopleListHeaderViewCell(title: Strings.Title.MutualFriends, numberOfPeople: 0)
if section == 1
{
//mutualFriendsSectionView.layoutSubviews()
return mutualFriendsSectionView
}
}