The label outlet is invalid - ios

I want to declare the 4 labels which in my table prototype cells so that I can retrieve all the data from Parse into the label. As you see in the picture, there're 4 labels, I want each of them have their own outlet, but it showing me the invalid outlet error.
I'm using the Parse to do it, so that the superclass of the prototype cell will be the PFTableViewCell.
class TimetableViewController: PFQueryTableViewController, UITextFieldDelegate{
#IBOutlet weak var lblTime: UILabel!
The error that I got will be like this...
The lblTime outlet from the TimetableViewController to the UILabel is
invalid. Outlets cannot be connected to repeating content.
Therefore, what should I do to avoid this problem exist?

You need to create a custom subclass of UITableViewCell and declare your IBOutlets there. Then you use that subclass instead of the generic UITableViewCell throughout your main view controller.
To reiterate: elements inside a tableview cell belong to the cell, not to the view controller that contains everything.
Edit:
In your view controller, you would conform to UITableView's delegate & datasource protocols (and implement any methods that are relevant to what you're trying to accomplish). You would handle populating (initial) cell data in the follow data source method:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier", forIndexPath: indexPath) as! TimetableViewCell
// TODO: setup cell data here
return cell
}

Cells are generated on the fly. There is no real connection between the controller and the cell so you cannot connect something in the cell to a controller. Specifically, usually you have multiple cells of the same type ("repeated content") and you can't have all of the labels connected to one outlet in the parent controller.
Typically, what you want to do is declare a class for the cell, e.g.
class MyCell : UITableCell {
#IBOutlet weak var lblTime: UILabel!
}
and add the outlet to it.

For those that errors still exist after you delete the IBOutlet code from your view controller you still need to right click it and delete the old connection. After deleting it the error message will go away.
This cleared all my errors. Hope will help others as well.

Related

student list on button click in swift

In my main.storyboard there has "all student" button. I need to open student list when "all student" button will be clicked.
Students are already saved in realm db. So far I've done below:-
Have dragged view controller from object library and have placed in empty space.
Have also dragged table view and table view cell inside view controller.
Created a modal segue from "all student" button to this view controller.
Have given cell identifier to "Cell" and segue identifier to "rList"
In vieController, I've made the following changes:-
Class vieController: UIvieController, UITextfieldDelegate
to below:
Class vieController: UIvieController, UITextfieldDelegate, UITableViewDelegate, UITableViewDatasource.
but getting below error in viewDidLoad:
fatal error: unexpectedlyfound nil while unwrapping an optional value
on below line:
table1.dataSource = self
Not getting how I'll achieve this student list. Any help would be appreciated.
Delete the line table1.dataSource = self
Then go to the Connections Inspectors of tableView from storyboard
after that drag the dataSource to your viewController
also make sure that your tableView outlet is connected properly.
I hope this help you
First, you should check to make sure that you have a proper table view outlet in your view controller. I show in my screenshot how the table view outlet is created.
You can then use
self.tableView.dataSource = self
in your viewDidLoad.
As far as getting the data to show, you can put your data into an array property in your view controller.
If the data is being loaded from the network, then the table view should be reloaded using tableView.reloadData() after the data has loaded.
The other pieces that you seem to be missing are the required data source methods for a UITableViewDataSource.
There are two functions that are required and they belong in your view controller.
I’ve provided minimal outlines below to get you started.
func tableView(tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
// The cell identifier is set in your storyboard.
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
// Do stuff like set values on labels in the cell.
cell.label.text = “text to display”
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
// Return the number of cells to be displayed.
return 10
}

Populating text field in prototype cell

Currently I have a few of custom cell's prototypes created in Storyboard with text fields embedded in them. To access these text fields, I use nameTextField = cell.viewWithTag:(1) in cellForRowAtIndexPath:. But viewDidLoad: and viewWillAppear: methods get called before cellForRowAtIndexPath, so at that time nameTextField is nil. To populate text fields when table view shows on screen, I use viewDidAppear:, but it results in a noticeable delay. Also, when I scroll table view up and down, cellForRowAtIndexPath: gets called again and again, resetting already entered data in text fields.
Are there more efficient ways to populate text fields embedded in custom cells' prototypes with data just before the view shows up, and to prevent resetting of entered data in each cellForRowAtIndexPath: call?
I guess you're creating profile screen (or something with many textField to get input data from user). Am I right?
If I'm right, you can use a static tableView (when you have a few textFields)
Hope this can help.
I'm not sure I understand completely what you're trying to do, but cells are normally configured in the cellForRowAtIndexPath: method, not in viewDidLoad. You can also try connecting the textfield to an outlet on your custom cell class. Then you can do:
// in view controller
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
as! CustomCell
let object = myDataSource[indexPath.row]
cell.textField.text = object.description
cell.shouldBecomeFirstResponder = indexPath.row == 0
return cell
}
// then in the cell
class CustomCell: UITableViewCell {
#IBOutlet weak var textField: UITextField!
var shouldBecomeFirstResponder: Bool = false
override func awakeFromNib() {
if shouldBecomeFirstResponder {
textField.becomeFirstResponder()
}
}
}
Then when users input text into the textfield, it would make sense to update your data source.
In viewDidLoad try to run something like self.tableView.reloadData before you do this line "nameTextField = cell.viewWithTag:(1)".

ios swift how to interact with outlets in custom cell

nomrally i have one view controller and i add outlets to it. and inside view did load i can change the font of the text view or i can add images to the ui image. but now i have a custom cell like this:
class NumberOfPeopleTableViewCell: UITableViewCell {
#IBOutlet weak var numberOfPeopleLabel: UILabel!
as you see, i have outlet in that cell, how can i interact with that outlet? there is no view did load function inside the table view cell
You could set the font of the label in your storyboard.
Or you could set the font of the label in awakeFromNib (a method you can override in your cell class).
Or you could set the font of the label in tableView(_:cellForRowAtIndexPath:) (in your table view controller).
From what I can gather, the "standard" approach would be, inside your UITableViewController subclass:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("<Your Id Here>", forIndexPath: indexPath) as! NumberOfPeopleTableViewCell
let foo = cell.numberOfPeopleLabel // DO STUFF WITH IT
// Do more stuff here
return cell
}
OR --
If you want to keep your View Controller code clean of graphics layout-ing / appearance logic (which you should) consider, inside NumberOfPeopleTableViewCell to override func layoutSubviews().
OR (my favourite) --
You could subclass the UITextView (e.g. MYCellTextView) and change the appearance for all of your subclass instances in your app delegate using UIApparence. Like this should work:
MyCellTextView.appearance().font = UIFont(name: "<myFont>", size: 10.0)
You can put the above, for example, in your app delegate. This has the advantage of keeping appearance code in one place and away from view controllers (and generic, for all instances of your custom view).
You can override the function layoutSubviews
override func layoutSubviews() {
//do whatever here for your outlets
}
take a look at awakeFromNib. as the documentation states:
When an object receives an awakeFromNib message, it is guaranteed to have all its outlet instance variables set.
so you can do:
override func awakeFromNib() {
super.awakeFromNib()
numberOfPeopleLabel.font = UIFont.systemFontOfSize(15.0) // or whatever font you want to assign
}

Swift: prevent cells with text in UITableViewCell from being re-initialized after scrolling

In my iOS app I have a UITableViewController with many cells and some of them contain a UITextField so that the user can insert text. The "problem" is that if, after entering the text in the right cell, the user scrolls down the table and then scrolls up it, then those cells are initialized again and the text il blank again. Is there a way to prevent this? So that the cells are initialized only when the table is scrolled down... Thank you
With reference to my comment to the initial code and code provided.
Many developers implement UITableViewDatasource methods in a natural way.
Put inside cellForRowAtIndexPath a conditional switch/case block and dependent on indexPath.row dequeue and return reusable cell. This is ok, but this also means that you need to put one more switch/case block into heightForRowAtIndexPath and probably into numberOfRowsInSection and didSelectRowAtIndexPath.
What if you are in need of changing the order of cells in tableview, or in need of inserting new cell in between existing cells or something else. This cause to the significant rewrite of the existing code.
The good practice for the the predefined tableviews (known amount and order of rows) is to create an Object describing tableview cells and access it from all those UITableViewDatasource, UITableViewDelegate methods. This Object also could be used for storing the value of the dynamic elements in cells and could be updated accordingly.
Let say it's an array of NSDictionary's (mutable once if we decide to store data inside).
let cellsData : [[String: String]] = [["type": "TextField","value": ""], ["type": "DatePicker","value": ""], ["type": "TextField","value": "Default Value"]]
In your UITableViewDatasource, UITableViewDelegate method you access your cellsData array using indexPath.row get the NSDictionary object parse it, and dependent on the value of "type" key, dequeue proper cell. You will also have to switch/case block everywhere, but you check the value from cellsData Object not indexPath.row itself. So you can update you tableview, just by updating cellsData object. You can also put height into it etc.
I see you keep references from cells dequeued in tableview, for accessing them to retrieve data, but it's not needed if you have all actual data stored in the cellsData Object.
How to achieve it? Listen to events inside cell. Create custom events, and trigger them from cell.
To create custom event, you will need to create your custom delegate class (Reference Implementing a Delegate for a Custom Class)
The Swift concept is very similar to Objective-C. First we need to create the delegate protocol class:
protocol BigTextCellDelegate {
func controller(controller: BigTextCell, textFieldDidEndEditingWithText: String, atIndex: Int)
}
Then you need to declare a delegate property inside your custom cell class.
var delegate: BigTextCellDelegate?
Now you need to implement it in your tableview class, first make your tableview class conforming to BigTextCellDelegate protocol in a way.
class DetailsNewTaskViewController: UITableViewController, BigTextCellDelegate {
...
}
Then we need to implement BigTextCellDelegate, just place a method inside DetailsNewTaskViewController.
func controller(controller: BigTextCell, textFieldDidEndEditingWithText: String, atIndex: indexRow) {
// #todo: update `cellsData` at indexRow with `textFieldDidEndEditingWithText` text
}
Now you need to make your custom cell to listed to UITextFieldDelegate events and trigger our custom BigTextCellDelegate event.
First you need to make it conforming to UITextFieldDelegate protocol and then assign it during the initialization, you can achieve the same from Storyboard.
class BigTextCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
var Int: rowIndex
var delegate: BigTextCellDelegate?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
textField.delegate = self
}
func textFieldDidEndEditing(textField: UITextField) {
delegate?.controller(self, textFieldDidEndEditingWithText: textField.text, atIndex: rowIndex)
}
}
The delegate property of type BigTextCellDelegate is optional as we can't be sure it's not nil.
Now you need to assign your tableview to listen to BigTextCellDelegate events.
At cellForRowAtIndexPath, put:
cell = tableView.dequeueReusableCellWithIdentifier(...)
cell.delegate = self
cell.rowIndex = indexPath.row
// #todo: get data from cellsData array and assign it back to cell.textField.text
That's all.
As for the DatePicker and other cells. You can do it exactly in the same way.
Assign to valueChanged of DatePicker from inside the cell and trigger the method on new custom delegate protocol.
datePicker.addTarget(self, action: Selector("dataPickerChanged:"), forControlEvents: UIControlEvents.ValueChanged)
func datePickerChanged(datePicker:UIDatePicker) {
// #todo: trigger event
}

Pass data object to a UITableViewCell and use it from within custom cell controller

I have a basic method for populating a tableView with a custom cell in Swift
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let object = array[UInt(indexPath!.row)] as Word
var cell:DictionaryTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("dictionaryCell") as DictionaryTableViewCell
cell.originalText.text = object.original
return cell
}
Works fine. Now, I got a custom cell DictionaryTableViewCell with custom properties and some IBActions (for different buttons inside that cell).
My question is: How do I expose data that was passed to the cell from tableView and use it from inside my custom cell controller? For instance I would like to be able to manipulate it for each cell using IBActions.
For now my custom cell controller is nothing fancy
class DictionaryTableViewCell: UITableViewCell {
#IBOutlet weak var originalText: UILabel!
#IBAction func peak(sender: AnyObject) {
}
}
Is there a custom property I can use to recover data passed onto it? Or do I have to implement some sort of a protocol? If so - how?

Resources