Initialize optional UIActivityIndicatorView in Swift - swift

I have no idea what I am doing wrong. In my TableViewController, I want each cell to have a UIActivityIndicator when tapped. So in my TableViewCell class I have the following:
#IBOutlet weak var loadingIcon: UIActivityIndicatorView!
And in TableViewController I have the following:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "taskCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? TodayTableViewCell else {
fatalError("The dequeued cell is not an instance of TodayTableViewCell.")
}
let task = tasks[indexPath.row]
cell.nameLabel.text = task.name
cell.descriptionLabel.text = task.description
cell.timeRangeLabel.text = task.timeRangeLabel
cell.currentTime.text = String(format:"%f", task.currentTime)
cell.totalTime.text = String(format:"%f", task.totalTime)
cell.taskIcon.image = task.icon
cell.loadingIcon = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
cell.loadingIcon.hidesWhenStopped = true
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt
indexPath: IndexPath){
let cell = (TodayTableViewCell)();tableView.cellForRow(at: indexPath)
print("tapped")
tasks[indexPath.row].isActive = !tasks[indexPath.row].isActive
if(tasks[indexPath.row].isActive) {
//Loading.start()
cell.loadingIcon.startAnimating()
}
else {
//Loading.stop()
cell.loadingIcon.stopAnimating()
}
}
I get fatal error: unexpectedly found nil while unwrapping an Optional value but I have no idea why because it looks like I am initializing it.
I get:
EXC_BAD_INSTRUCTION
Here is the storyboard:
Now back to the error I was getting earlier:

As you can see in the image, you can set that property on the storyboard. You can find on the right panel of your xcode.
If you still want to write that line you should connect the UIActivityIndicator to the IBOutlet

Related

Swift How should Custom Cell load tableview data and make it expand when I use didSelectRowAt?

I create a custom cell that include tableview
Here's the MainTableView and data
var data = [People(name:"Kevin",age:"18",tall:"180")]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainCell", for: indexPath) as! MainTableViewCell
cell.title = data[indexPath.row].name
cell.detail = ["age \(data[indexPath.row].age)","tall \(data[indexPath.row].tall)"]
cell.isExtend = false
return cell
}
I try to tap cell to expand tableView height and load data
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainCell", for: indexPath) as! MainTableViewCell
cell.isExpand = !cell.isExpand
}
Here's the MainTableViewCell
class MainTableViewCell: UITableViewCell {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var detailTableView: UITableView!
#IBOutlet weak var detailTableViewHeight: NSLayoutConstraint!
var detail:[String] = []{
didSet{
detailTableView.reloadData()
}
}
var isExpand: Bool = false{
didSet{
detailTableView.isHidden = !isExpand
detailTableView.reloadData()
detailTableViewHeight.constant = isExpand ? detailTableView.contentSize.height:0
}
}
override func awakeFromNib() {
super.awakeFromNib()
detailTableView.delegate = self
detailTableView.dataSource = self
detailTableView.isScrollEnabled = false
detailTableViewHeight.constant = 0
}
}
I use tableView to load data and hide some of theme first, and tapped to show and hide theme
but It happened nothing
Did I forgot something?
In cellforRowAt:
let cell: MoreUserDetails = tableView.dequeueReusableCell(withIdentifier: "MoreUserDetails") as! MoreUserDetails
cell.backgroundColor = .clear
cell.selectionStyle = .none
if isExpand {
// your func when its expanded
}
else {
// your func when its hidden
}
return cell
in did select
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
if isSelected[indexPath.row] {
isExpand[indexPath.row] = false
}
else {
isExpand[indexPath.row] = true
}
self.tableVIew.reloadData()
}

Setting imageView in cell

i am new to Swift and I have seen tons of guides on the topic. However in my case, it's working. I have a custom cell file:
class FileCell: UITableViewCell {
#IBOutlet weak var firstName: UILabel!
#IBOutlet weak var cellImage: UIImageView!
func updateImage(name: String) {
cellImage.image = UIImage(named: name)
}}
In the view controller I am using "willDisplay" function as follows:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "FileCell") as! FileCell
let user = users[indexPath.row]
if user.email.isEmpty {
//cell.cellImage.image = UIImage(named: "folder.png")
cell.updateImage(name: "folder.png")
} else {
//cell.cellImage.image = UIImage(named: "file.png")
cell.updateImage(name: "file.png")
}
}
where i try to change imageView in cell depending on the data incoming to cell. However, the images either don't display at all or cells are not showing up.
Thanks in advance for tips on what i am doing wrong.
You should not dequeue a new cell, since you already have one.
Just skip the first statement:
// let cell = tableView.dequeueReusableCell(withIdentifier: "FileCell") as! FileCell
But one question: Why are you using the willDisplay delegate method? I would suggest to set up the cell in tableView(_:cellForRowAt:):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "FileCell") as! FileCell
let user = users[indexPath.row]
cell.firstName.text = user.name // or something
if user.email.isEmpty {
cell.updateImage(name: "folder.png")
} else {
cell.updateImage(name: "file.png")
}
return cell
}

A sub view in UITableview gets disappear once the row is been clicked.

I'm working on a project in swift 3.0 where I have a UIView inside a UITableViewCell. For some reason once a row is been selected the view gets disappear, and once a a new row is been selected the view of the previous cell shows up and the view of the newly selected one gets disappear.Name of the view that gets disappear is redView(reference of the code bellow). My code and UITableView delegates as follow.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.clear
cell.selectedBackgroundView = backgroundView
let data = self.mediaList[indexPath.row] as! NSDictionary
let redView = cell.viewWithTag(TABLE_CELL_TAGS.redView)!
let reducedPriceLabel = cell.viewWithTag(TABLE_CELL_TAGS.reducedpricelable) as! UILabel
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.title, text: data["title"] ?? "title...")
if let reducedPrice = data["mediaValue"] as? Int{
reducedPriceText = "$\(String(reducedPrice))"
redView.isHidden = false
reducedPriceLabel.isHidden = false
}else{
redView.isHidden = true
reducedPriceLabel.isHidden = true
}
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.reducedpricelable, text: reducedPriceText)
return cell;
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}
Go to the storyboard setting of tableViewcell set selection to None. then I think it will work for you.
Try this and let me know.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}

Thread 1 EXC error

I've been creating a firebase database but I have one error that I just can't get past. It says:
thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)'
It's probably something simple that I'm just looking past. Any Ideas?
Here's the code & the error is on the line of code:
//
// Database.swift
// intern
//
// Created by Lani Daniels on 8/20/17.
// Copyright © 2017 Lani Daniels. All rights reserved.
//
import UIKit
import Firebase
import FirebaseDatabase
struct PostStruct {
let title: String
let message: String
}
class DatabaseViewController: UITableViewController {
var posts: [PostStruct] = []
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let label1 = cell.viewWithTag(1)as! UILabel
label1.text=posts[indexPath.row].title
// ERROR BELOW:thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)
let label2 = cell.viewWithTag(2)as! UILabel
label2.text=posts[indexPath.row].message
return cell
}
}
For the first error:
let cell = tableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
Change tableview to tableView
For the second one:
It seems like you're trying to access to the outlet that might be not a UILabel. check this by making optional biding like:
let label2 = cell.viewWithTag(2) as? UILabel
and check that label using breakpoint. It might be nil.
Also it is better to use a custom cell class with two labels as outlets and then dequeue that custom cell in the cellForRowAt method:
class CustomCell: UITableViewCell {
#IBOutlet weak var firstLabel: UILabel!
#IBOutlet weak var secondLabel: UILabel!
}
And then
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? CustomCell
cell?.firstLabel.text=posts[indexPath.row].title
cell?.secondLabel.text=posts[indexPath.row].message
return cell!
}
And don't forget to set that custom class for the cell in the interface builder

Swift 3 Breaks Cell For Row At Index Path

This code was from a now inactive tutorial that helped me load in data to a table view. Since the tutorial was written in Swift 2.0, I believe that this was changed in Swift 3. I know that the override function itself was changed, which I handled. But now, it brings me a Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0) error.
Update: I have tried multiple things including creating a custom class for the cell. I still either get the same error I listed above, or a Thread 1: Signal SIGABRT error on the first line of my App Delegate file. Creating a breakpoint hasn't helped me because I know where the error is coming from.
import UIKit
import Firebase
import FirebaseDatabase
struct postStruct {
let title : String!
let message : String!
}
class LoggedInController: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
let message = snapshotValue!["message"] as? String
self.posts.insert(postStruct(title: title, message: message), at: 0)
self.tableView.reloadData()
})
post()
}
func post(){
let title = "Title"
let message = "Message"
let post : [String : AnyObject] = ["title" : title as AnyObject,
"message": message as AnyObject]
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").childByAutoId().setValue(post)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell!
}
}
Update 2: Here is the new code I used. It's not pretty and only gets the title.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell?.textLabel?.text = posts[indexPath.row].title
cell?.detailTextLabel?.text = posts[indexPath.row].message
return cell!
} else {
let label1 = cell?.viewWithTag(1) as? UILabel
label1?.text = posts[indexPath.row].title
let label2 = cell?.viewWithTag(2) as? UILabel
label2?.text = posts[indexPath.row].message
return cell!
}
}
Using dequeueReusableCell, you are accessing cell which doesn't exists. To make your code work change the below line:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
To
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
Ok this code let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") produces an optional called cell that may or may not contain a a valid instance of UITableViewCell. Optionals in Swift are a way to safeguard against nil values, you can read more about optionals here: Optionals
On the first run when your table view wants to load its data it calls all the required methods of your UITableViewDataSource. The first run is a critical one because there aren't any instances of the UITableViewCell the table view can dequeue yet. To solve your problem you have to do something similar to the code below:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
} else {
cell?.textLabel?.text = "" //reset value
cell?.detailTextLabel?.text = "" // resetValue
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
}
}
Code similar to the one above are usually used to programmatically add an instance of UITableViewCell. However, if you used interface builder to add a prototype cell use the let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) method to dequeue your cells in which case it does not return an optional and you do not need to do all the if / else blocks.
Something else I wanted to mention about your code is finding sub views buy their ID will not produce a very object oriented code and that maybe the source of your errors where the compiler can not find the sub views. The better way would be to use one of the built in instances of UITableViewCell such as .default or alliteratively you could subclass the said class and make your very own custom cells.
Hope this helped!
Try this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell
}
Edited
Make Sure you did these things
UITableViewController
In viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier:"catCell" )
let catNib : UINib = UINib.init(nibName: "TableViewCategoryCell", bundle: nil)
self.tableView.register(catNib, forCellReuseIdentifier: "TableViewCategoryCell")
In cellForRowAt indexPath
let cell : OPM_AlarmTableViewCategoryCell = tableView.dequeueReusableCell(withIdentifier:"OPM_AlarmTableViewCategoryCell" ) as! OPM_AlarmTableViewCategoryCell!
cell.categoryLabel?.text = "Some Text"
return cell
UITableviewCell.XIB
Hope u did these things
UITableviewCell
Make sure the dot appears so that the #IBOutlet is connected with the
xib label