Blank Table View Cell - ios

I am trying to post a picture in a table view cell, but it keeps coming back blank. I have 3 files that I've created for this.
First is a data file with the picture information:
import Foundation
class Data {
class Entry {
let filename : String
let heading : String
init(fname : String, heading : String) {
self.heading = heading
self.filename = fname
}
}
let pic = [
Entry(fname: "Picture1.jpg", heading: "Heading 1"),
]
}
Then I have my table view controller
import UIKit
class TableViewController: UITableViewController {
let data = Data()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.pic.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as TableViewCell
let entry = data.pic[indexPath.row]
let image = UIImage(named: entry.filename)
cell.pic.image = image
return cell
}
}
The third is the cell itself
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet var selfie: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
I have no clue why the cell is coming back blank. I have the image file stored in Supporting Files.
Can anyone help me?

Updated my answer:
Make sure that you registered your UITableViewCell subclass before calling the dequeueReusableCellWithIdentifier:forIndexPath: method. Just add the following line into your viewDidLoad method:
self.tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "Cell")

You have to assign the image to the UITableViewCell's imageView
Updated Try:
cell.selfie.image = image
instead of cell.pic.image = image

2 possible reason:
First one is, your UITableViewCell contains an image view named selfie but you are setting pic.
So, try cell.selfie.image = UIImage(named: entry.filename);
Second one is, are you sure you are getting the image form UIImage(named: entry.filename); ?
Hope this helps.. :)

Related

UITableView does not populate with data

I am trying to make a simple UITableView with custom cells (including two labels and one image view) but I can't get the table to be populated with data.
I have created the following struct for my data:
struct feed {
var title: String
var subtitle: String
var image: String
}
and here I have defined some sample data:
var myfeed = [feed(title: "Test Feed", subtitle: "Welcome to feedFeed", image: "https://www.demo.com/imnage1.png"), feed(title: "Number 2", subtitle: "Demo?", image: "https://www.demo.com/imnage2.png")]
I have created an UITableView in my Storyboard, have configured the Custom cell and am using the Cell identifier "LabelCell".
I have created a separate cocoaTouchclass file for the UITableViewCell class:
import UIKit
class ehappyTableViewCell: UITableViewCell {
#IBOutlet weak var headlineTitleLabel: UILabel!
#IBOutlet weak var headlineTextLabel: UILabel!
#IBOutlet weak var headlineImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
func tableView(_ tableView: UITableViewCell, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 100.0;//Choose your custom row height
}
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
In my ViewController file I have the following code:
#IBOutlet weak var table: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myfeed.count
}
func tableView(_ tableViwq: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ehappyTableViewCell = self.table.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath) as! ehappyTableViewCell!
let headline = myfeed[indexPath.row]
cell.headlineTitleLabel?.text = headline.title
cell.headlineTextLabel?.text = headline.subtitle
let urlWithoutHTTP = headline.image
let httpAddition = "https:"
let addition = "\(httpAddition)\(urlWithoutHTTP)"
let url = URL(string: addition)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
DispatchQueue.main.async {
cell.headlineImageView.image = UIImage(data: data!)
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 140.0;//Choose your custom row height
}
override func viewDidLoad() {
super.viewDidLoad()
self.table.delegate = self
self.table.dataSource = self
}
When I run the app the table will not populate with the sample data I have created.
Any suggestions on what I can do?
If your cell is an xib then you have to register the cell by writing the following code in the viewDidLoad
self.table.register(UINib(nibName: "ehappyTableViewCell", bundle: nil), forCellReuseIdentifier: "LabelCell")
If it is designed inside the viewcontroller in storyboard then no need to register
Check if delegate and dataSource are given
Try replacing the line with following line
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell") as? ehappyTableViewCell

Segue from TableView into another Tableview using gesture

I have FirstTableView (TableView) which is populated by cells that have an image and label. If users tap the label, I want to segue into another tableview (SecondTableView), which will use the label from the previous tableview as a path(foldername) to search for images within that folder and display them as cells.
I have bits and pieces of the code written together, but I'm not quite sure where to pass the perform segue and prepare for segue functions.
Here is the extension of my FirstTableViewController, which populate the cells of the FirstTableView:
FirstTableView
extension FirstTableViewController: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataCells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let folderCell = dataCells[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstTableCell") as! FirstTableViewCell
cell.setCell(cell:folderCell)
return cell
}
}
Here is the code for the FirstTAbleViewCell. Notice that I've created the UITapGestureRecognizer constant and a protocol. If the FolderLabel is clicked, I want to segue into the next tableview.
func setCell is just the function to populate the FirstTableViews.
FirstTableViewCells
import UIKit
protocol LabelCellDelegate {
func func1(sender:Any)
}
class FirstTableViewCell: UITableViewCell {
#IBOutlet weak var ImageView: UIImageView!
#IBOutlet weak var FolderLabel: UILabel!
var delegate: LabelCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
FolderLabel.isUserInteractionEnabled = true
let recognizer = UITapGestureRecognizer(target: self, action:Selector(("handleTap:")))
recognizer.numberOfTapsRequired = 1
self.FolderLabel.addGestureRecognizer(recognizer)
}
func handleTap(recognizer: UITapGestureRecognizer){
delegate!.func1(sender: self)
}
func setCell (cell : FolderCell){
self.ImageView.image = cell.image
self.FolderLabel.text = cell.label
}
}
Next is the SecondTableViewController.
Somehow, after the tap of the cell from the FirstTableView I want to get the label name that was tapped, and use that name as a directory to search.
Grab all the images within the directory and display them as images in cells in SecondTableView. I'm not quite sure where I should be calling the gesture function and which TableViewController should be the delegate of the cell protocol.
SecondTableView
import UIKit
class SecondTableViewController: UIViewController {
var Imagefiles: [String] //Imagefiles String. This are all images from tapped folder label.
var CellObjects: [folderCell] // Cellobjects to fill the cells. contains images and image names.
// need to get folder name from FirstTableViewCell how?
override func viewDidLoad() {
super.viewDidLoad()
imageFiles = getImageObjects(folder: Foldercell) //how to get access to folderCell???????
cellObjects = createArray(imageFiles: imageFiles)
}
func getImageObjects(folder: FolderCell) -> imageFiles: String {
//FUNCTION To search tapped label and grab all image file paths.
func createArray(imageFiles: string)-> tempArray: [folderCell]{
//We use this function to take the image files from above function and
//create cell objects to populate our cells
//in SecondTableView
}
}
}
}
extension ViewController: LabelCellDelegate{
func1(folderLabel : String) {
return folderLabel
}
}
extension LablesTableView:UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return CellObjects.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellFolderObject = folderObjects[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondCell") as! LabelCell
let folderCell = CellObjects[indexPath.row]
cell.setCell(cell: folderCell)
return cell
As you can see, I haven't called perform segue and prepare for segue. I'm not sure where I should be calling them.
I'm also unsure about where the delegate to the gesture protocol should be.
Thank you.
Inside cellForRowAt set
cell.delegate = self
//
then inside this delegate function of the VC ( conform to the protocol LabelCellDelegate )
extension FirstTableViewController:LabelCellDelegate {
func func1(sender: FirstTableViewCell) {
self.performSegue(withIdentifier: "goToSecond", sender:sender.FolderLabel.text!)
}
}
//
the VC method is triggered from here
func handleTap(recognizer: UITapGestureRecognizer){
delegate!.func1(sender: self)
}
//
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondController = segue.destination as? SecondTableViewController {
secondController.sendedStr = sender as! String
}
}

I was wondering how to make a cell go to another view controller in Xcode 9, swift

I've been trying to figure out how to configure a cell to go to another view, in this case, I'm listing a group of services after login and when the user taps on a service they like, it takes them to a map. But I don't know how to set the cell up in a way that it takes them to the map when its tapped. I've tried creating a segue but nothing happens when the cell is tapped. I'm new to programming and was wondering if someone could explain this.
I've watched a bunch of youtube videos which gave me the understanding on how to set up the cell (basic stuff).
Would really appreciate some advice, thanks!
Hope this post helps anyone that's dipping their feet into the programming journey!
Thank you, happy coding!
Here is the code I currently have:
import UIKit
struct cellData {
let cell : Int!
let text : String!
let image : UIImage! }
class ListServicesTVC: UITableViewController {
var arrayOfCellData = [cellData]()
override func viewDidLoad() {
arrayOfCellData = [cellData(cell : 1, text : "Barber Services", image : #imageLiteral(resourceName: "barberservice") ),
cellData(cell : 2, text : "Salon Services", image : #imageLiteral(resourceName: "salonservice"))]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfCellData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if arrayOfCellData[indexPath.row].cell == 1 {
let cell = Bundle.main.loadNibNamed("BarberServiceCell", owner: self, options: nil)?.first as! BarberServiceCell
cell.barberImageView.image = arrayOfCellData[indexPath.row].image
cell.barberServicesLabel.text = arrayOfCellData[indexPath.row].text
return cell
}
else if arrayOfCellData[indexPath.row].cell == 2 {
let cell = Bundle.main.loadNibNamed("SalonServicesCell", owner: self, options: nil)?.first as! SalonServicesCell
cell.salonImageView.image = arrayOfCellData[indexPath.row].image
cell.salonServicesLabel.text = arrayOfCellData[indexPath.row].text
return cell
}
else {
let cell = Bundle.main.loadNibNamed("BarberServiceCell", owner: self, options: nil)?.first as! BarberServiceCell
cell.barberImageView.image = arrayOfCellData[indexPath.row].image
cell.barberServicesLabel.text = arrayOfCellData[indexPath.row].text
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if arrayOfCellData[indexPath.row].cell == 1 {
return 120
}
else if arrayOfCellData[indexPath.row].cell == 2 {
return 120
}
else {
return 120
}
}
}
Just follow the steps below:
create A tableView Outlet in ViewController Class.
create a TableViewCell Class and register with tableView Outlet.
then, create a DetailViewController Class ( i.e, When You click on a particular cell, it should show details of that particular cell)
In main "ViewController" do the following code
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {'
#IBOutlet var tableView: UITableView!
var tableData: [String] = ["Apple", "Samsung", "LG"]
// 1
override func viewDidLoad() {
super.viewDidLoad()
// Register customCell with tableView Outlet
let nib = UINib(nibName: "CustomTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
}
// 2
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.count
}
// 3
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: CustomTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! CustomTableViewCell
// injecting data to cell
cell.lblCompanyName.text = tableData[indexPath.row]
cell.imgCompanyName.image = UIImage(named: tableData[indexPath.row])
return cell
}
// 4
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let detailObj=DetailViewController(nibName: "DetailViewController", bundle: nil)
self.navigationController?.pushViewController(detailObj, animated: true)
detailObj.nameVar=tableData[indexPath.row]
detailObj.imgStr=tableData[indexPath.row]
}
In "CustomTableViewCell" class
class CustomTableViewCell: UITableViewCell {
#IBOutlet var imgCompanyName: UIImageView!
#IBOutlet var lblCompanyName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}}
in "DetailViewController"
class DetailViewController: UIViewController {
#IBOutlet var name: UILabel!
#IBOutlet var image: UIImageView!
var nameVar:String?
var imgStr:String?
override func viewDidLoad() {
name.text=nameVar
image.image=UIImage(named: imgStr!)
super.viewDidLoad()
// Do any additional setup after loading the view.
}}
End of the Code
I think I am clear, if you have any quires just comment below.
Hi try the following set of code, I have added few additional changes in your code which is necessary for passing the details, I hope it will solve your issue.
I have added only the extra codes which you needed
class ListServicesTVC: UITableViewController {
// Add this variable in this class and use it whereever you needed it in this class
var selectedItem: cellData?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Now maintain the selected data in the local variable we declared
selectedItem = arrayOfCellData[indexPath.row]
// Now perform the segue operation
performSegue(withIdentifier: "VIEW_CONTROLLER_IDENTIFIER_OF_MAP_CLASS", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "VIEW_CONTROLLER_IDENTIFIER_OF_MAP_CLASS" {
let destinationVC = segue.destination as? VIEW_CONTROLLER_IDENTIFIER_OF_MAP_CLASS
destinationVC?.selectedItem = self.selectedItem // Pass the selected item here which we have saved on didSelectRotAt indexPath delegate
}
}
In Second class:
class VIEW_CONTROLLER_IDENTIFIER_OF_MAP_CLASS: UIViewController {
// Add this variable in this class and use it whereever you needed it in this class
var selectedItem: cellData?

Not using reusable cell in UITableView with CollectionView in each cell

I have a UITableView and in its prototype cell have a UICollectionView.
MainViewController is delegate for UITableView and
MyTableViewCell class is delegate for UICollectionView.
On updating each TableViewCell contents I call cell.reloadData() to make the collectionView inside the cell reloads its contents.
When I use reusable cells, as each cell appears, it has contents of the last cell disappeared!. Then it loads the correct contents from a URL.
I'll have 5 to 10 UITableViewCells at most. So I decided not to use reusable cells for UITableView.
I changed the cell creation line in tableView method to this:
let cell = MyTableViewCell(style: .default, reuseIdentifier:nil)
Then I got an error in MyTableViewCell class (which is delegate for UICollectionView), in this function:
override func layoutSubviews() {
myCollectionView.dataSource = self
}
EXC_BAD_INSTRUCTION CODE(code=EXC_I386_INVOP, subcode=0x0)
fatal error: unexpectedly found nil while unwrapping an Optional value
MyTableViewCell.swift
import UIKit
import Kingfisher
import Alamofire
class MyTableViewCell: UITableViewCell, UICollectionViewDataSource {
struct const {
struct api_url {
static let category_index = "http://example.com/api/get_category_index/";
static let category_posts = "http://example.com/api/get_category_posts/?category_id=";
}
}
#IBOutlet weak var categoryCollectionView: UICollectionView!
var category : IKCategory?
var posts : [IKPost] = []
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
if category != nil {
self.updateData()
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func layoutSubviews() {
categoryCollectionView.dataSource = self
}
func updateData() {
if let id = category?.id! {
let url = const.api_url.category_posts + "\(id)"
Alamofire.request(url).responseObject { (response: DataResponse<IKPostResponse>) in
if let postResponse = response.result.value {
if let posts = postResponse.posts {
self.posts = posts
self.categoryCollectionView.reloadData()
}
}
}
}
}
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath as IndexPath) as! MyCollectionViewCell
let post = self.posts[indexPath.item]
cell.postThumb.kf.setImage(with: URL(string: post.thumbnail!))
cell.postTitle.text = post.title
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//You would get something like "model.count" here. It would depend on your data source
return self.posts.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
}
MainViewController.swift
import UIKit
import Alamofire
class MainViewController: UITableViewController {
struct const {
struct api_url {
static let category_index = "http://example.com/api/get_category_index/";
static let category_posts = "http://example.com/api/get_category_posts/?category_id=";
}
}
var categories : [IKCategory] = []
override func viewDidLoad() {
super.viewDidLoad()
self.updateData()
}
func updateData() {
Alamofire.request(const.api_url.category_index).responseObject { (response: DataResponse<IKCategoryResponse>) in
if let categoryResponse = response.result.value {
if let categories = categoryResponse.categories {
self.categories = categories
self.tableView.reloadData()
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return self.categories.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.categories[section].title
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionHolderTableViewCell") as! MyTableViewCell
let cell = MyTableViewCell(style: .default, reuseIdentifier:nil)
cell.category = self.categories[indexPath.section]
cell.updateData()
return cell
}
}
MyCollectionViewCell.swift
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var postThumb: UIImageView!
#IBOutlet weak var postTitle: UILabel!
var category : IKCategory?
}
Why not reusing cells caused this? Why am I doing wrong?
There are a few things to do that should get you up to speed.
First, uncomment the line that uses reusable cells and remove the line of code that creates the non-reusable cells. It is safe to use reusable cells here.
Second, in MyTableViewCell, set the dataSource for the collection view right after the super.awakeFromNib() call. You only need to set the dataSource once, but layoutSubviews() will potentially get called multiple times. It's not the right place to set the dataSource for your needs.
override func awakeFromNib() {
super.awakeFromNib()
categoryCollectionView.dataSource = self
}
I have removed the call to updateData() from awakeFromNib(), as you are already calling it at cell creation. You can also delete the layoutSubviews() override, but as a general rule, you should be careful to call super.layoutSubviews() when overriding it.
Lastly, the reason the posts seemed to re-appear in the wrong cells is that the posts array wasn't being emptied as the cells were reused. To fix this issue, add the following method to MyTableViewCell:
func resetCollectionView {
guard !posts.isEmpty else { return }
posts = []
categoryCollectionView.reloadData()
}
This method empties the array and reloads your collection view. Since there are no posts in the array now, the collection view will be empty until you call updateData again. Last step is to call that function in the cell's prepareForReuse method. Add the following to MyTableViewCell:
override func prepareForReuse() {
super.prepareForReuse()
resetCollectionView()
}
Let me know how it goes!

UITableViewCell's contents' alpha changes on its own

I've got a simple ViewController -- let's call it SettingsViewController -- which contains a UITableView with some custom cells containing a UILabel.
Whenever I load said SettingsViewController the UILabel inside the 1st cell gets its alpha set to some small number on its own, I don't ever change the value of any alphas. Also, the highlighting works as expected on pressing the cells. Sometimes, when I return to SettingsViewController from a different one, it's a different random cell, possibly 2 or 3 cells.
Here's a gif of what happens when I first load the SettingsViewController:
I'm using Swift 2.0 with Xcode 7.0.1 and running this code on iOS 8.4.1 as well as 9. I've also seen this happen in a UICollectionView with cells containing only a UIImageView - in that case it was the UIImageView whose alpha would get changed.
Here's my code for the SettingsViewController:
class SettingsViewController: BronzeBaseViewController {
#IBOutlet var settingsTable: UITableView!
private let textCellIdentifier = "Cell"
private let settingsList = ["Account Details", "About this App", "Terms of Service", "Privacy Policy"]
override func viewDidLoad() {
super.viewDidLoad()
self.settingsTable.delegate = self
self.settingsTable.dataSource = self
}
}
// MARK: - UITableViewDataSource methods
extension SettingsViewController: UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(self.textCellIdentifier, forIndexPath: indexPath) as! SettingsTableViewCell
let row = indexPath.row
cell.titleLabel.text = self.settingsList[row]
cell.titleLabel.tag = row
cell.backgroundColor = getBackgroundColor()
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.settingsList.count
}
}
// MARK: - UITableViewDelegate methods
extension SettingsViewController: UITableViewDelegate {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch(indexPath.row) {
case 0 :
self.performSegueWithIdentifier("accountDetailsSegue", sender: self)
case 1:
self.performSegueWithIdentifier("legalViewSegue", sender: self)
case 2:
self.performSegueWithIdentifier("legalViewSegue", sender: self)
case 3:
self.performSegueWithIdentifier("legalViewSegue", sender: self)
default:
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
And here's the class I'm using for the actual cells:
class SettingsTableViewCell: UITableViewCell {
#IBOutlet var titleLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
let titleFont = UIFont(name: "ProximaNovaSoft-Regular", size: self.titleLabel.font.pointSize)
self.titleLabel.font = titleFont
}
}
Any idea what might be causing this and how to fix it properly?

Resources