Swift: Cannot put my value into label (optional issue) - ios

I have my value from Firebase but Swift doesn't want to put it in my label.
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
To summarize, my database look like that:
Firebase database
I've created a standard model call ServiceModel:
import Foundation
class ServiceModel {
var name: String?
var category: String?
var pricing: String?
init(name: String?, category: String?, pricing: String?){
self.name = name
self.category = category
self.pricing = pricing
}
}
I want to display this values into a TableView, so I've created a custom cell like this (very standard too):
import UIKit
class SubscriptionTableViewCell: UITableViewCell {
#IBOutlet weak var imageService: UIImageView!
#IBOutlet weak var labelName: UILabel!
#IBOutlet weak var labelCategory: UILabel!
#IBOutlet weak var labelPricing: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
And now, here is the controller of my view:
import UIKit
import FirebaseDatabase
class SecondViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
var refServices:DatabaseReference!
#IBOutlet weak var ListSub: UITableView!
var serviceList = [ServiceModel]()
var databaseHandle:DatabaseHandle?
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return serviceList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath) as! SubscriptionTableViewCell
let service: ServiceModel
service = serviceList[indexPath.row]
//cell.imageService.image = UIImage(named: service.name! + ".png")
cell.labelName?.text = service.name //ERROR HERE
cell.labelCategory?.text = service.category
cell.labelPricing?.text = service.pricing
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
ListSub.delegate = self
ListSub.dataSource = self
refServices = Database.database().reference().child("Categories");
refServices.observe(DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
self.serviceList.removeAll()
for services in snapshot.children.allObjects as! [DataSnapshot] {
let serviceObject = services.value as? [String: AnyObject]
let serviceName = serviceObject?["Name"]
let serviceCategory = serviceObject?["Category"]
let servicePricing = serviceObject?["Pricing"]
let service = ServiceModel(name: serviceName as! String?, category: serviceCategory as! String?, pricing: servicePricing as! String?)
self.serviceList.append(service)
}
self.ListSub.reloadData()
}
})
}
When I launch this view, I have the error mentioned earlier.
When I debug, I see that I have the right values in service.name, service.category and service.pricing
It seems that I don't correctly handle Optional values, but I cannot see what is wrong.
Thanks for your help.

Potential lines to be crashed in case of optional unwrapping is this line
refServices = Database.database().reference().child("Categories");
refServices.observe(DataEventType.value, with: { (snapshot) in
Try to pur breakpoint and check if refServices is initialised properly or make ti to be optional not using !
Hope this help
Ps. please remove ; out of your Swift code :P

Use this code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath) as! SubscriptionTableViewCell
let service = serviceList[indexPath.row]
// If you sure that you have to display all the info use this code
if let name = service.name, let category = service.category, let price = service.pricing {
cell.labelName.text = name
// set other data also here....
}
// If you know any value may be empty or not exists then use this code.
if let name = service.name {
cell.labelName.text = name
}
if let category = service.category {
cell.labelCategory.text = service
}
if let pricing = service.pricing {
cell.labelPricing.text = pricing
}
return cell
}

Did you register your custom UITableViewCell with your tableView? Put this line into the init() function of your ViewController:
ListSub.register(SubscriptionTableViewCell.classForCoder(), forCellReuseIdentifier: "SubCell")

If you debug this function, what did you see for your service
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCell", for: indexPath) as! SubscriptionTableViewCell
let service: ServiceModel
//Put a breakpoint here
service = serviceList[indexPath.row]
//Put a breakpoint here
//cell.imageService.image = UIImage(named: service.name! + ".png")
cell.labelName?.text = service.name
cell.labelCategory?.text = service.category
cell.labelPricing?.text = service.pricing
return cell
}

Related

How to utilize a custom tableview cell nib in iOS with a swipe table view controller as the cell's default controller

I am a beginner and I'm having some issues with an iOS app I'm creating. I am utilizing the SwipeCellKit package to have swipeable cells for my tableViews. I would also like to use a custom cell to display birthdays. I created a custom tableView cell and nib. The issue that I'm running into is properly coding the nib into my birthday tableView controller so it will display the information. Below is a picture of my code. I'd really appreciate if someone could point me in the right direction.
import UIKit
import RealmSwift
import UserNotifications
class BirthdayTableViewController: SwipeTableViewController {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var birthdayLabel: UILabel!
#IBOutlet weak var age: UILabel!
let realm = try! Realm()
var birthdays: Results<Birthday>?
let dateFormatter = DateFormatter()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(BirthdayTableViewCell.nib(), forCellReuseIdentifier: BirthdayTableViewCell.identifier)
tableView.rowHeight = 100
tableView.separatorStyle = .none
}
override func viewWillAppear(_ animated: Bool) {
loadBirthdays()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return birthdays?.count ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
guard let birthdayCell = (tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! BirthdayTableViewCell) else {fatalError()}
let birthday = birthdays?[indexPath.row]
let firstName = birthday?.firstName ?? ""
let lastName = birthday?.lastName ?? ""
name?.text = firstName + " " + lastName
if let date = birthday?.birthdate as Date? {
birthdayLabel?.text = dateFormatter.string(from: date)
} else {
birthdayLabel.text = " "
}
return cell
}
[Beginning of Code][1]
[TableView Methods][2]
[1]: https://i.stack.imgur.com/fZspG.png
[2]: https://i.stack.imgur.com/9IlD1.png
The app crashes due to casting a result of
tableView.dequeueReusableCell(withIdentifier:for:)
with force unwrap as! which returns non optional object.
To solve the error, just change it to as?
There is another thing which can lead to an error as well, you typed direct identifier of a cell instead using the identifier BirthdayTableViewCell.identifier
guard let birthdayCell = (tableView.dequeueReusableCell(withIdentifier: BirthdayTableViewCell.identifier, for: indexPath) as? BirthdayTableViewCell) else {fatalError()}

pass image to another view when clicked on tableview cell. The image is fetched from json data and initialised with alamofire

i am fetching json data from url and displaying it in tableview. I want to image in tableview to another view controller when clicked on tableview cell. My another label are showing but dont know how to write code for image in didselectrowatindexpath method of tableview
my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
//getting hero for specified position
let hero: Hero
hero = heroes[indexPath.row]
//displaying values
cell.labelName.text = hero.name
cell.labelTeam.text = hero.team
cell.labelRealName.text = hero.realname
cell.labelAppear.text = hero.firstappearance
cell.labelPublish.text = hero.publisher
//displaying image
Alamofire.request(hero.imageUrl!).responseImage { (response) in
debugPrint(response)
if let image = response.result.value {
cell.heroImage.image = image
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let heroesDetails:HeroesDetailsViewController = self.storyboard?.instantiateViewController(withIdentifier: "HeroesDetailsViewController") as! HeroesDetailsViewController
heroesDetails.strlabelTeam = heroes[indexPath.row].team
heroesDetails.strlabelName = heroes[indexPath.row].name
heroesDetails.strlabelAppear = heroes[indexPath.row].firstappearance
heroesDetails.strlabelPublish = heroes[indexPath.row].publisher
heroesDetails.strlabelRealName = heroes[indexPath.row].realname
self.navigationController?.pushViewController(heroesDetails, animated: true)
}
my heroesdetailviewcontroller file where i want to display code:
import UIKit
class HeroesDetailsViewController: UIViewController {
#IBOutlet weak var detailsImg: UIImageView!
#IBOutlet weak var detailsName: UILabel!
#IBOutlet weak var detailsRealName: UILabel!
#IBOutlet weak var detailsTeam: UILabel!
#IBOutlet weak var detailsAppear: UILabel!
#IBOutlet weak var detailsPublisher: UILabel!
var strheroImage: UIImage!
var strlabelName: String!
var strlabelTeam: String!
var strlabelAppear: String!
var strlabelPublish: String!
var strlabelRealName: String!
override func viewDidLoad() {
super.viewDidLoad()
detailsImg.image = strheroImage
detailsName.text = strlabelName
detailsRealName.text = strlabelRealName
detailsTeam.text = strlabelTeam
detailsAppear.text = strlabelAppear
detailsPublisher.text = strlabelPublish
// Do any additional setup after loading the view.
}
}
my modal file:
class Hero{
var name:String?
var team:String?
var imageUrl:String?
var realname:String?
var firstappearance:String?
var publisher:String?
init(name:String?, team:String?, imageUrl:String?, realname:String?, firstappearance:String?, publisher:String?) {
self.name = name
self.team = team
self.imageUrl = imageUrl
self.realname = realname
self.firstappearance = firstappearance
self.publisher = publisher
}
}
my tableviewcell.swift file:
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var heroImage: UIImageView!
#IBOutlet weak var labelName: UILabel!
#IBOutlet weak var labelTeam: UILabel!
#IBOutlet weak var labelAppear: UILabel!
#IBOutlet weak var labelPublish: UILabel!
#IBOutlet weak var labelRealName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
my main viewcontroller.swift file which contains all code:
import UIKit
import Alamofire
import AlamofireImage
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
//MARK: IBOUTLETS
#IBOutlet weak var tableviewHeroes: UITableView!
// Web API Url
let URL_GET_DATA = "https://simplifiedcoding.net/demos/marvel/"
// List to store Heroes
var heroes = [Hero]()
//implementing uirefreshcontrol to tableview
lazy var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(ViewController.handleRefresh), for: .valueChanged)
refreshControl.tintColor = UIColor.init(red: 217/255, green: 133/255, blue: 199/255, alpha: 1)
return refreshControl
}()
override func viewDidLoad() {
super.viewDidLoad()
self.tableviewHeroes.addSubview(self.refreshControl)
//fetching data from web api
Alamofire.request(URL_GET_DATA).responseJSON { (response) in
//getting json
if let json = response.result.value {
//converting json to NSArray
let heroesArray:NSArray = json as! NSArray
//traversing through all elements of the array
for i in 0..<heroesArray.count {
//adding heroes value to hero list
self.heroes.append(Hero(
name: (heroesArray[i] as AnyObject).value(forKey: "name") as? String, team: (heroesArray[i] as AnyObject).value(forKey: "team") as? String, imageUrl: (heroesArray[i] as AnyObject).value(forKey: "imageurl") as? String,
realname: (heroesArray[i] as AnyObject).value(forKey: "realname") as? String, firstappearance: (heroesArray[i] as AnyObject).value(forKey: "firstappearance") as? String, publisher: (heroesArray[i] as AnyObject).value(forKey: "publisher") as? String ))
}
//display data in tableview
self.tableviewHeroes.reloadData()
}
}
self.tableviewHeroes.reloadData()
}
func handleRefresh(refreshControl: UIRefreshControl) {
self.tableviewHeroes.reloadData()
refreshControl.endRefreshing()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return heroes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
//getting hero for specified position
let hero: Hero
hero = heroes[indexPath.row]
//displaying values
cell.labelName.text = hero.name
cell.labelTeam.text = hero.team
cell.labelRealName.text = hero.realname
cell.labelAppear.text = hero.firstappearance
cell.labelPublish.text = hero.publisher
//displaying image
Alamofire.request(hero.imageUrl!).responseImage { (response) in
debugPrint(response)
if let image = response.result.value {
cell.heroImage.image = image
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let heroesDetails:HeroesDetailsViewController = self.storyboard?.instantiateViewController(withIdentifier: "HeroesDetailsViewController") as! HeroesDetailsViewController
let hero: Hero
hero = heroes[indexPath.row]
let image : UIImage = UIImage(data: hero.imageUrl)
heroesDetails.strlabelTeam = heroes[indexPath.row].team
heroesDetails.strlabelName = heroes[indexPath.row].name
heroesDetails.strlabelAppear = heroes[indexPath.row].firstappearance
heroesDetails.strlabelPublish = heroes[indexPath.row].publisher
heroesDetails.strlabelRealName = heroes[indexPath.row].realname
heroesDetails.strheroImage = image
self.navigationController?.pushViewController(heroesDetails, animated: true)
}
}
You should use Caches policy instead of passing downloaded image from one VC to another. Larger image could take time to download, user can not wait for it before tapping the table view cell.
For more details please see Image Cache Section
https://github.com/Alamofire/AlamofireImage
In your didSelectRowAt indexPath function, before sending image to different viewController try to convert the data into image first, then send it:
First declare a global image variable:
var imageArray = [UIImage]()
Then assign the image you get from alamofireImage to this variable in your cellForRowAt indexPath function:
if let image = response.result.value {
cell.heroImage.image = image
self.imageArray.append(image)
}
Then pass it :
heroesDetails.strlabelTeam = heroes[indexPath.row].team
heroesDetails.strlabelName = heroes[indexPath.row].name
heroesDetails.strlabelAppear = heroes[indexPath.row].firstappearance
heroesDetails.strlabelPublish = heroes[indexPath.row].publisher
heroesDetails.strlabelRealName = heroes[indexPath.row].realname
heroesDetails.strheroImage = self.imageArray[indexPath.row]
1st View Controller:
import UIKit
import Alamofire
import ObjectMapper
var homeScreenData = [HomeDataModel]()
func homeScreenDataAPI(){
var params : Parameters?
params =
[
"user_id" : id ?? 0,
]
print(params as Any)
self.view.makeToastActivity(.center)
ApiCallWithHeader(url : “homeDataAPI” , params : params!) { responseObject, error in
// use responseObject and error here
print("responseObject = \(String(describing: responseObject)); error = \(String(describing: error))")
let JSON = responseObject
if(JSON?["status"] as? String == "success") {
if let responseData = (JSON?["data"] as? [Dictionary<String, AnyObject>]) {
if let homeScreenDataValue = Mapper<HomeDataModel>().mapArray(JSONObject: responseData)
{
self.homeScreenData = homeScreenDataValue
}
}
return
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
vc.homeScreenData = homeScreenData
vc.indexTagValue = indexPath.item
self.navigationController?.pushViewController(vc, animated: true)
}
Second View Controller:-
var homeScreenData = [HomeDataModel]()
var indexTagValue = 0
extension HomeScreenDetailViewController : UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return homeScreenData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : HomeDataOtherCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCollectionViewCell", for: indexPath as IndexPath) as! testCollectionViewCell
cell.nameLabel.text = homeScreenData[indexPath.item].name
if let image = homeScreenData[indexPath.item].user_image {
if image.contains("https://") {
cell.userImageView.sd_setImage(with: URL(string: image ), placeholderImage: UIImage(named: "userIcon"))
} else {
let userImage = ImageURL + image
// userImageView.image = UIImage(named: userImage )
let urlString = userImage.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
cell.userImageView.sd_setImage(with: URL(string: urlString ?? ""), placeholderImage: UIImage(named: "userIcon"))
}
} else {
cell.userImageView.image = UIImage(named: "userIcon")
}
return cell
}
ImageURL in my app is
let ImageURL = "http://test/public/images/
It is recommended to pass the data model so that it can reduce a lot of unnecessary code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellid = "testCellID"
var cell = tableView.dequeueReusableCell(withIdentifier: cellid)
if cell==nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellid)
}
let hero: Hero
hero = heroes[indexPath.row] as! Hero
cell?.textLabel?.text = hero.name
let url = URL(string: hero.imageUrl ?? "")
let data = try! Data(contentsOf: url!)
cell?.imageView?.image = UIImage(data: data)
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let hero = heroes[indexPath.row] as! Hero
let heroesDetails = HeroesDetailsViewController()
heroesDetails.hero = hero
self.navigationController?.pushViewController(heroesDetails, animated: true)
}
class HeroesDetailsViewController: UIViewController {
#IBOutlet weak var detailsImg: UIImageView!
var hero: Hero!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: hero.imageUrl ?? "")
let data = try! Data(contentsOf: url!)
self.detailsImg?.image = UIImage(data: data)
}
}

Load/Download image from SDWebimage and display in Custom tableView cell imageView

i already parsed other values but how will i show image to imageView i m already using SdWebImage in Swift.I want to show that in Bottom cell "detail" Below is my code
import UIKit
import SystemConfiguration
import MBProgressHUD
public struct Section {
var arrayDataTop: String
var arrayTerms: String
var qrImage:String
var collapsed: Bool
public init( arrayDataTop: String,qrImage: String ,arrayTerms: String, collapsed: Bool = false) {
self.arrayDataTop = arrayDataTop
self.qrImage = qrImage
self.arrayTerms = arrayTerms
self.collapsed = collapsed
}
}
class CollapsibleViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableViewCollapsible:UITableView!
#IBOutlet weak var listImage:UIImageView!
var nodatastr:String = "No Deal Found."
var dealIDCollapsible : String?
var dealDictCollapsible = [String: AnyObject]()
var parentNavigationController: UINavigationController?
private var loadingView:MBProgressHUD?
var sectionDataObj = [Section]()
override func viewDidLoad() {
super.viewDidLoad()
if (!self.isInternetAvailable()){
self.alertMessageShow(title: "No Internet Connection", message: "Make sure your device is connected to the internet.")
}
else{
if self.loadingView == nil {
self.loadingView = MBProgressHUD.showAdded(to: self.view, animated: true)
}
tableViewCollapsible.estimatedRowHeight = 100.0
tableViewCollapsible.layoutIfNeeded()
tableViewCollapsible.updateConstraintsIfNeeded()
tableViewCollapsible.tableFooterView = UIView()
self.listImageFetch()
dealFetchParticularListing()
}
}
func dealFetchParticularListing(){
let prs = [
"listing_id":dealIDCollapsible,//dealIDCollapsible,
"Deal_fetch_listing": "1" as String
]
Service.CreateDeal(prs as [String : AnyObject]?, onCompletion: { result in
let json = result as? NSDictionary
if let data = json as? [String:Any]{
if let err = data["status"] as? String, err == "success"{
if let data = data["result"] as? [Any]{
//
//fill your data in that local Section obj
//
var sectionDataObj = [Section]()
for sectionObj in data{
if let sectionObjVal = sectionObj as? [String:Any]{
if let qrcode = sectionObjVal["qrcode"] as? String{
if let tnc = sectionObjVal["tnc"] as? String{
if let deal_title = sectionObjVal["deal_title"] as? String{
let sectionValue = Section(arrayDataTop: deal_title, qrImage: qrcode, arrayTerms: tnc)
// access main objects/UIelement on main thread ONLY
sectionDataObj.append(sectionValue)
}
}
}
}
}
DispatchQueue.main.async { () -> Void in
self.sectionDataObj.removeAll()
//
//assign ur data in main sampleData(Section obj) then reload tableView with that data.
//
self.sectionDataObj = sectionDataObj
self.tableViewCollapsible.reloadData()
self.loadingView?.hide(true)
}
}
}
}
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Header
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "header") as! MyCellData
cell.lblDealTitle.text = sectionDataObj[indexPath.section].arrayDataTop
return cell
}
// Cell
let cell = tableView.dequeueReusableCell(withIdentifier: "detail") as! MyCellData
cell.lblTerm.text = sectionDataObj[indexPath.section].arrayTerms
// here i want to show image
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension//320.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
let collapsed = !sectionDataObj[indexPath.section].collapsed
// Toggle collapse
sectionDataObj[indexPath.section].collapsed = collapsed
self.tableViewCollapsible.reloadSections([indexPath.section], with: .automatic)
}
}
}
class MyCellData:UITableViewCell{
#IBOutlet weak var lblDealTitle: UILabel!
#IBOutlet weak var dealimage: UIImageView!
#IBOutlet weak var lblTerm: UILabel!
#IBOutlet weak var qrCodeImage: UIImageView!
}
Plz help me with this.thanks in advance.All things are working properly i am able to see other details.Help will be appreciated.Plz help me i m struggling with this issue.
update ur tableView cellForRowAt like so to show an image or ur cell from ur sectionDataObj
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Header
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "header") as! MyCellData
cell.lblDealTitle.text = sectionDataObj[indexPath.section].arrayDataTop
return cell
}
// Cell
let cell = tableView.dequeueReusableCell(withIdentifier: "detail") as! MyCellData
cell.lblTerm.text = sectionDataObj[indexPath.section].arrayTerms
let imgUrl = sectionDataObj[indexPath.section]. qrImage
cell.qrCodeImage.sd_setImage(with: URL(string:imgUrl), completed: nil)
return cell
}

FireBase is returning strings as nil

Man, UITableView's just do not want to work with me. I have been outputting strings to Firebase storage and I see the values stored. My problem is that I cannot output any of those strings into the UITableView. I just see a blank table view and when I go and try to see what is being outputted by thoughtObjects.thoughts it just says "nil." If anyone can help figure out what is wrong that would be appreciated. Thank you so much StackOverflow.
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var inputThoughtTextField: UITextField!
#IBOutlet weak var successfulUploadLbl: UILabel!
#IBOutlet weak var tableView: UITableView!
var refThoughts: DatabaseReference!
var thoughtList = [ThoughtModel]()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return thoughtList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
//creating a cell using the custom class
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! VCTableViewCell
//the artist object
let thoughtObjects: ThoughtModel
//getting the artist of selected position
thoughtObjects = thoughtList[indexPath.row]
//adding values to labels
cell.wordCloud.text = thoughtObjects.thoughts
//print(cell.wordCloud.text)
//returning cell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
refThoughts = Database.database().reference().child("thoughts");
refThoughts.observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.thoughtList.removeAll()
//iterating through all the values
for thoughts in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let thoughtsObject = thoughts.value as? [String: AnyObject]
let thoughtText = thoughtsObject?["thoughts"]
let thoughtId = thoughtsObject?["id"]
//creating artist object with model and fetched values
let thoughtCreation = ThoughtModel(id: thoughtId as! String?, thoughts: thoughtText as! String?)
//appending it to list
self.thoughtList.append(thoughtCreation)
}
//reloading the tableview
self.tableView.reloadData()
}
})
}
#IBAction func buttonAddThought(_ sender: UIButton){
addThought()
}
func addThought(){
let key = refThoughts.childByAutoId().key
let thought = ["id": key,
"Thoughts": inputThoughtTextField.text! as String
]
refThoughts.child(key).setValue(thought)
successfulUploadLbl.text = "Thought Uploaded"
}
}

How do I add a UIButton into my UITableViewCell in Swift 3?

I have an existing UITableView that displays data and is working fine.
However I now want to add an info button into this UITableViewCell.
I added the UIButton directly into the TableViewCell in storyboard. I then tried to declare this button as an outlet but I got the error
"Outlets cannot be connected to repeating content."
I read around the subject and decided to create a new subclass called "
import UIKit
class PersonalStatsTableViewCell: UITableViewCell {
#IBOutlet weak var personalStatsInfoButton: UIButton!
var selectedCellTitle: String?
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
As you can see I have declared the UIButton personalStatsInfoButton in this sub-class.
With more reading around the subject I believe I need to add something like:
personalStatsInfoButton.tag = indexPath.row
personalStatsInfoButton.addTarget(self, action: "infoButtonClicked", forControlEvents: UIControlEvents.TouchUpInside)
and then have a function:
function infoButtonClicked(sender:UIButton){
let infoCell = sender.tag
print (infoCell)
}
My issue is I don't know whether I need to take all my existing tableView code and transfer it into the the new sub-class PersonalStatsTableViewCell or just the parts that deal with the info button.
Below is my existing VC code that initially deals with the TableView prior to adding in this new button.
import UIKit
class ShowCommunityViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var membersTableView: UITableView!
#IBOutlet weak var communityName: UILabel!
var communityIsCalled: String?
var comIds = [String]()
var communityId: Int?
var selectedCellTitle: String?
var cellId: Int?
var communityPlayerIds = [String]()
var communityPlayers = [String?]()
override func viewDidLoad() {
super.viewDidLoad()
communityName.text = (communityIsCalled)
self.membersTableView.delegate = self
self.membersTableView.dataSource = self
membersTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.communityPlayers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PersonalStatsTableViewCell", for: indexPath as IndexPath)
cell.textLabel?.text = self.communityPlayers[indexPath.row]
cell.textLabel?.font = UIFont(name: "Avenir", size: 12)
cell.textLabel?.textColor = UIColor.white // set to any colour
cell.layer.backgroundColor = UIColor.clear.cgColor
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedCellTitle = self.communityPlayers[indexPath.row]
cellId = indexPath.row
}
override func viewDidAppear(_ animated: Bool) {
let myUrl = URL(string: "http://www.???.uk/???/specificCommunity.php?");
var request = URLRequest(url:myUrl!);
request.httpMethod = "POST";
let postString = "id=\(comIds[communityId!])";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
if error != nil {
print("error=\(error)")
return
}
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
if let arr = json?["players"] as? [[String:String]] {
self.communityPlayerIds = arr.flatMap { $0["id"]!}
self.communityPlayers = arr.flatMap { $0["user_name"]!}
self.membersTableView.reloadData()
print ("names: ",self.communityPlayers)
}
} catch{
print(error)
}
}
}
task.resume()
}
}
You don't need to put any code in your class PersonalStatsTableViewCell you can manage all the things from ShowCommunityViewController what you need to done is in your cellForRowAt method add this
cell.personalStatsInfoButton.tag = indexPath.row
cell.personalStatsInfoButton.addTarget(self, action: #selector(infoButtonClicked(sender:), forControlEvents: UIControlEvents.TouchUpInside)
and add this function
function infoButtonClicked(sender:UIButton){
let infoCell = sender.tag
print (infoCell)
}
Your code and what you are thinking is correct, you just need to change the following line.
Apart from what Arun B has said, you need to make sure xcode knows what kind of class cell will belong to.
let cell = tableView.dequeueReusableCell(withIdentifier: "PersonalStatsTableViewCell", for: indexPath as IndexPath)
should be
let cell = tableView.dequeueReusableCell(withIdentifier: "PersonalStatsTableViewCell", for: indexPath as IndexPath) as! PersonalStatsTableViewCell
This happens if the custom class is not set up properly. Make sure that PersonalStatsTableViewCell is set as the Custom class of the UITableViewCell in your storyboard.

Resources