IBAction on UISwitch in custom UITableViewCell causes error - ios

I have a UITableViewController and a custom TableViewCell and within that UITableViewCell there is a UISwitch. This switch is wired to an IBAction, but as soon as i tap the switch, i get an error:
unrecognised selector sent to instance 0x13ce30a50
SelectFriendsViewController.swift
class SelectFriendsViewController: UITableViewController, SelectorDelegate {
func selectUser(string: String) {
selectedUser = string;
}
.... lots of code removed for simplification.
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:SelectorTableViewCell = tableView!.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as SelectorTableViewCell;
cell.delegate = self;
}
}
protocol SelectorDelegate {
func selectUser(string: String)
}
class SelectorTableViewCell: UITableViewCell {
#IBOutlet var swUser: UISwitch! = UISwitch();
#IBOutlet var lblUserName: UILabel! = UILabel();
var delegate: SelectorDelegate!
#IBAction func SwitchUser(sender: UISwitch) {
//delegate.selectUser("test");
//even with just this println i get the error
println("test");
}
}

You have some strange stuff in this code:
your cellForRowAtIndexPath should return a cell (you probably have done this, and just didn't copy it across to your stackoverflow question)
You're generating your UISwitch either from storyboard or xib as you say 'the switch on the storyboard is highlighted' - however you're also instantiating these in code!
eg.
#IBOutlet var swUser: UISwitch! = UISwitch();
But I believe your problem in the end is related to your IBAction 'SwitchUser'. You either renamed this method at some point or created an IBAction earlier and then deleted it. To check the current status of your IBActions, click on your cell in the storyboard or xib and open the Connections Inspector. I bet you'll find your problem there.

Try changing the function name to switchUser instead of SwitchUser
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_243

Related

Button Action from UITableViewCell to ViewController

I am trying to implement the Delegate way to do some action on a button tap from my UITableViewCell to a ViewController. The following is what I have so far -
TableViewCell:
protocol UserCellDelegate : class {
func disableUser(cell: UserCell, button: UIButton)
}
class UserCell : UITableViewCell {
#IBOutlet weak var userLabel: UILabel!
#IBOutlet weak var userDescription: UILabel!
#IBOutlet weak var writeOutUser: UIButton!
weak var delegate: UserCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
writeOutUser.layer.cornerRadius = 5.0
}
#IBAction func disableUserButtonAction(sender: UIButton) {
delegate?.disableUser(self, button: writeOutUser) //self here I believe to be the cell
}
}
ViewController:
class UserDetailTableViewController : UIViewController, UserCellDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let userCell = UserCell()
userCell.delegate = self
}
func disableUser(cell: UserCell, button: UIButton) {
print("VC: User Disabled")
}
}
The problem here is, the disableUser function in my ViewController never gets called. What am I doing wrong?
What is the best way to do it?
I had referred to the SO Approved Answer Here which is what I am following the same, but with no luck.
Any help will be appreciated. Thanks!!
You should set the delegate of your cell in the cellForRowAtIndexPath method.As #vadian said,In the viewDidLoad you should not initialize your cell using default initializer, and the delegate is nil for your cell by this way in viewDidLoad.
Either initialise your cell using the init(style: reuseIdentifier) or set the delegate in the cell for row method as you will initialize the cell in that method anyway.
When you're doing this:
let userCell = UserCell()
userCell.delegate = self
You are setting the delegate of userCell, and only the delegate of userCell. I'm sure that the table view cells displayed in your table view is not userCell.
So instead of setting the delegate of userCell, you should set the delegate of the cells that you actually want to show in the table view. The most probable place to create new cells that you want to show in table view is in the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) method.
In the method, you must have something like this:
let cell = ...
// setting properties of cell using the model
return cell
You just need to add this line before the return:
cell.delegate = self
In your code UserCell acts like a UIView. You forgot adding userCell to current controller's view. If you want to use UITableViewCell, the better way is using it with UITableView.

Swift Custom TableViewCell wont show labels

I have a custom cell class called CurrentFilesCell with the setting code below
class CurrentFileCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var statusImage: UIImageView!
var currentContent: AircraftContent! {
didSet{
setStyles(Constants.appStyleSetting)
nameLabel.text = currentContent.contentName
dateLabel.text = currentContent.contentStatus
}
}
Within my CurrentFilesViewController I simply set it within cellForRowAtIndexPath
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CurrentFileCell", forIndexPath: indexPath) as? CurrentFileCell
cell?.currentContent = content
return cell!
}
I believe I also have everything linked correctly, as I have done something similar to this in other classes, both with cells and vc's.
My problem is that It does not load anything when run, there is no default text and no updated text after it should have been set. Here is an image showing the linkage
http://imgur.com/qlK4d5O
I'm really not sure what is going on and why this isn't working. I have tried deleting it and recreating but I must be missing something.
EDIT
Here is a picture of the debugger showing that the cell's currentContent is not empty. This is taken right before the return cell! is executed.
http://imgur.com/O250qXq
Did you register this cell in table view? If not than dqueRqusableCellWithIdentifier will return nil value...
You can register it using UITableView function "registerNib: forCellReuseIdentifier:"
In the storyboard, you must define subclass of the prototype table cell.
And then, you must define identifier of the prototype table cell as "CurrentFileCell".
Then you will show the content of the table when the app will be run.

How can I call viewDidLoad in a UITableViewCell?

My code:
import Foundation
import Firebase
class CellOneViewController: UITableViewCell {
#IBOutlet weak var new1: UILabel!
let ref = Firebase(url: "https://burning-heat-8250.firebaseio.com/slide2")
func viewdidload() {
ref.observeEventType (.Value, withBlock: { snapshot in
self.new1.text = snapshot.value as? String
})
}
}
I've read around that you can't call viewDidLoad in a UITableViewCell, only in a UITableViewController. All the answers are in Objective-C, but I'm writing the app in Swift. I don't receive any critical errors but when running the app nothing appears in the cell where the label is. I'm fairly new to using Xcode, as I am just going around following guides so if I'm saying something incorrect let me know.
I think, you need method func layoutSubviews().
Only ViewController gets func viewDidLoad() called, after view is loaded.
If you need to initialize something or update views, you need to do in layoutSubviews(). As soon, your view or UITableViewCell gets loaded, layoutSubviews() get called.
Replace viewDidLoad with layoutSubviews()
class CellOneViewController: UITableViewCell {
#IBOutlet weak var new1: UILabel!
let ref = Firebase(url: "https://burning-heat-8250.firebaseio.com/slide2")
override func layoutSubviews() {
super.layoutSubviews()
ref.observeEventType (.Value, withBlock: { snapshot in
self.new1.text = snapshot.value as? String
})
}
}
The reason you can't do this is that a UITableViewCell isn't a subclass of UIViewController.
The cellForRowAtIndexPath method in the UITableViewDataSource is where you should set up your cells. You probably only want to do something like this in your custom UITableViewCell:
class CellOne: UITableViewCell {
#IBOutlet weak var new1: UILabel!
}
Then in your TableViewController's cellForRowAtIndexPath method (provided you have imported firebase) you should dequeue a reusable cell, cast it as a CellOne (as! cellOne) and then you can set the new1.text value. I don't know what your reuse identifier is, but it would look something like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Your-Reuse-Identifier", forIndexPath: indexPath) as! CellOne
cell.new1.text = "Your Value"
return cell
}

How do I create a custom UITableViewCell class in Swift?

I'm trying to follow along the following Using Auto Layout in UITableView for dynamic cell layouts & variable row heights top answer in Swift but for the IOS 7 version to mitigate some bugs in the IOS 8.
Right now, my custom cell class is:
class PostCell: UITableViewCell {
#IBOutlet var name: UILabel!
#IBOutlet var timestamp: UILabel!
#IBOutlet var postBody: 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
}
}
In my Storyboard I set my custom class as the class for the cell. I don't know if I have to use my reuseIdentifier anywhere. I don't know how to get that working in the next piece of code.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var cell = PostCell()
var post = self.posts[indexPath.row]
cell.name.text = post.name
cell.timestamp.text = post.timestamp
cell.postBody.text = post.body
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
cell.bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(feed.bounds), CGRectGetHeight(cell.bounds))
cell.setNeedsLayout()
cell.layoutIfNeeded()
var height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
height += 1.0
return height
}
I thought that would work, but when I call cell.name.text = post.name, I get an EXC_BAD_INSTRUCTION. I'm guessing the cell isn't properly hooked up to the storyboard somehow or something. How do I fix this?
The problem is that you don't understand how nibs work. You have set up your PostCell to be configured when it is loaded from its nib:
class PostCell: UITableViewCell {
#IBOutlet var name: UILabel!
}
So that means that name is nil - until this cell is instantiated from the nib, at which time the outlet will be hooked up. But then later you say:
var cell = PostCell()
But that is the wrong PostCell! You didn't load it from the nib; you just made one out of whole cloth. So since there was no nib-loading, the outlet (as you rightly suspect) was naturally never connected, and so cell.name is nil.
So the solution is: do not make one out of whole cloth. Load it from the nib.

Can't unwrap optional. No UITableViewCell

I've a table view that has a custom table view cell in it. My problem is that when I try and assign a value to a variable in the custom UITableViewCell I get the stated error. Now, I think its because the said variable is not initialised, but it got me completely stumped.
This is the custom table cell:
import Foundation
import UIKit
class LocationGeographyTableViewCell: UITableViewCell
{
//#IBOutlet var Map : MKMapView;
#IBOutlet var AddressLine1 : UILabel;
#IBOutlet var AddressLine2 : UILabel;
#IBOutlet var County : UILabel;
#IBOutlet var Postcode : UILabel;
#IBOutlet var Telephone : UILabel;
var location = VisitedLocation();
func Build(location:VisitedLocation) -> Void
{
self.location = location;
AddressLine1.text = "test";
}
}
My cell for row at index path is:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
var addressCell = tableView.dequeueReusableCellWithIdentifier("ContactDetail") as? LocationGeographyTableViewCell;
if !addressCell
{
addressCell = LocationGeographyTableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "ContactDetail");
}
addressCell!.Build(Location);
return addressCell;
}
As I say I'm completely baffled, the Build function calls the correct function in the UITableViewCell.
Any help will be gratefully appreciated.
Ta
I just made a simple project with your code, and I have a nil "AddressLine1" label, which causes the same error you have. I assume we have the same problem.
I solved it by adding the identifier "ContactDetail" to the prototype cell in my storyboard.
I also suggest that you change your code a little :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// This newer API ensures that you always get a cell, so no need for optionals.
// Also note the "let" that is preferred since you don't plan on changing addressCell
let addressCell = tableView.dequeueReusableCellWithIdentifier("ContactDetail", forIndexPath: indexPath) as LocationGeographyTableViewCell;
//addressCell.Build(Location); // the cell is a view, views should not know about model objects
addressCell.AddressLine1 = Location.addressLine1
// ... same for all labels, or do all that in a "configureCell" function
return addressCell;
}
I finally solved it. Instead of using the storyboard to define the UITableViewCell (as I'd done in the parent view controller) I created a Xib with the content and wired that up to the cell's class, referenced it in the TableViewController and allocated it in the cell created method.
viewDidLoad()
{
var nib = UINib(nibName: "LocationTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "locationCell")
}
var cell:LocationGeographyTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("locationCell") as LocationGeographyTableViewCell
cell.AddressLine1.text = "teetetette";
return cell;

Resources