Creating a Cocoa file - ios

I created a Cocoa file with a subclass of UITableViewCell so I could have an outlet to a prototype cell. Would this work?

Create an array with the titles for all your labels. For instance:
var titleLabels: [String] = ["Eggs", "Cheese", "Milk"]
Load your custom cell class (put this in viewDidLoad):
var nib = UINib(nibName: "YourCellSubclass", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
Then implement cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.detailLabel?.text = self.titleLabels[indexPath.row]
return cell
}
(Make sure you remember to set this class as the datasource for your tableview).
To include the quantities on the cells, you'll need another array of numbers (or better yet, an array of objects, each with a name and quantity attribute). Then (assuming your cell has two labels - one for the title, one for the quantity) you can set both the titleLabel and quantityLabel on your cell in the same manner as shown above.
This article has a pretty good walkthrough on creating custom tableview cells: https://www.weheartswift.com/swifting-around/

You could create the custom UITableViewCell with two UILabels, for example titleLabel and detailLabel. In the custom initWithStyle method, you can set the desired position of the labels within the cell.
After initializing the custom cell, you could write another method in the custom UITableViewCell class that sets the text values of titleLabel and detailLabel, and call that method from cellForRowAtIndexPath. The desired values could come from an NSArray, and you would use the cell row, indexPath.row, to fetch the corresponding values from the array.

Related

How to create tableview cells without using prototype cells?

In my tableview, every cell will be different and determined by a JSON response from server. And there will be infinite possibilities. So defining a prototype for each type of cell is not possible.
For example, one cell will have labels and buttons, another cell have images and buttons in different orders.
How to achieve this dynamic structure in tableview cells?
Currently what I am doing is: adding views as subview in cellForRowAtIndexPath but scrolling is very laggy this way.
How to achieve this without affecting performance this much
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! MyCell
for myview in data[indexPath.row].myviews{
cell.addSubview(myview)
}
return cell
}
If you're using a table view then your content is going to scroll vertically, right?
There is a physical limit to the amount of UI that you can put horizontally. Limited by the screen size.
So I'm guessing your UI parts are being laid out vertically in the cell?
So instead of laying out a button, label, image, another button, and a text field vertically in a cell...
Create a cell type called ButtonCell, LabelCell, ImageCell, MultiLineLabelCell, TextFieldCell, etc...
So now, instead of creating one cell with all these elements added. You instead create multiple cells each containing one type of UI. Now you can dequeue your cells in any particular order (driven by your JSON) and won't lose the performance.
The only solution I see is to have empty cell and add/remove subviews as needed. But you should add new subviews to a cell only if you did not add them before.
For example:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! MyCell
if cell.contentView.viewWithTag(1) == nil {
let label = UILabel()
label.tag = 1
cell.contentView.addSubview(label)
}
let label = cell.contentView.viewWithTag(1)
// label config there
return cell
}
Also don't forget to add subviews to cell's contentView not to cell itself.

How to use a custom UITableView and UITableViewCell inside a .xib file?

I'm creating a couple of cards with information to display. Each card is going to be represented with a UIView, so I'm creating each card in different .xib files.
One of my cards contains a custom UITableView and cells which are going to be loaded and managed with the UITableViewDataSource and UITableViewDelegate protocols.
However when I search for the Table View component and drag it to my .xib file it loads a predefined UITableView which I can't customize.
I'm fairly new to using separate .xib files (I've been using storyboards) so I don't know how to customize my TableView in this context so any help would be appreciated.
Xibs dont have the tableviewcell prototypes like in the storyboard, unfortunately its a storyboard only feature. Xibs are a bit archaic but still have their purpose. But you can have the different cells within the same xib file as your tableview, they will just be separate to the tableview.
you would load the xib like
var objects: NSArray?;
NSBundle.mainBundle().loadNibNamed("MyTableView", owner: self, topLevelObjects: &objects)
then in the array, depending on the order of the elements in the xib, you will get back an array of all the elements in your xib. so probably at position 0 will be your tableview, then 1 will be a cell, 2 a cell etc.. depending how many you have. you'll probably only load the cells in cellForRowAtIndexPath: only though, while the table will be in viewDidLoad or something
make a tableview and create a tableview instance.
write this code in viewdidload...
self.tableView.registerNib(UINib(nibName: "PackageDetailTVCell", bundle: nil), forCellReuseIdentifier: "Cell")
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return self.arrayDict.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! PackageDetailTVCell
let dict = self.arrayDict[indexPath.row]
cell.labelOfferPrice.text = (dict .objectForKey("offer_price") as! String)
cell.labelName.text = (dict .objectForKey("title") as! String)
cell.labelRegularPrice.text = (dict .objectForKey("price") as! String)
return cell
}

dequeueReusableCellWithIdentifier doesn't return cell

I have a static table with one static section. Other sections are dynamic.
I create Table Section and Table Cell for dynamic section. Set identifier for Cell, set custom class for it and even do:
self.tableView.registerClass(UncheckedStoreTableViewCell.self, forCellReuseIdentifier: "StoreCell")
if i don't register it with code, then i get:
'unable to dequeue a cell with identifier StoreCell - must register a
nib or a class for the identifier or connect a prototype cell in a
storyboard'
So when i use this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0 {
return super.tableView(tableView, cellForRowAtIndexPath: indexPath)
}
let cell = tableView.dequeueReusableCellWithIdentifier("StoreCell", forIndexPath: indexPath) as! UncheckedStoreTableViewCell
return cell
}
It works. But if i'm trying to change label: cell.myLabel.text = "one"
or just print(cell.myLabel) got
BAD_INSTRUCTION
You can definitely use dynamic cells in a static table view.
Don't expect a static table view to register your cell's identifier for you. Just do it yourself.
Do you have outlets in the cell class to some view in interface builder? If I were you I wouldn't expect the table view to know about that. It will instantiate your cell class, and that's it. No outlets will be set. I think this is related: load nib in view subclass
By the way, if you've defined a custom .nib for your cell, there's this method: registerNib(_:forCellReuseIdentifier:)
You do not need to register your cell in code.
You have correctly set the identifier of the cell, however this is not enough. In addition to this you also need to open Identity Inspector for your cell and set the class of the cell to be UncheckedStoreTableViewCell. Here is an image showing you where you should set it:
Without this step Xcode will not be able to correctly associate your cell identifier with your custom cell as it doesn't know anything about it!

swift custom UITableViewCell with TextView inside disappears

I am trying to get a custom tableView cell with a textView inside working in my tableView. I have made a custom UITableViewCell with a textView inside it.
I can get the custom made UITableViewCell with the textView inside to appear in the UITableView.
I can click inside the textView to type something, but when I finish typing and click on another tableViewCell, the first tableViewCell with the textView inside disappears. After disappearing, it becomes an empty tableViewCell. XCode gives this message:
"no index path for table cell being reused"
However, when I scroll away in the tableView and scroll back to the empty tableViewCell, it reappears.
I don't know how to keep the tableViewCell from disappearing. It seems like the answer has something to do with using the restorationIdentifier inside of UITableView, but I'm not sure how to use it. In the docs, it says to use restorationIdentifier for state preservation.
Here is the relevant code I have:
inside ViewDidLoad():
tableView.registerClass(PhotoAndRateTableViewCell.classForCoder(), forCellReuseIdentifier: ReuseIds.reviewCell)
tableView.registerNib(UINib(nibName: "PhotoAndRateTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: ReuseIds.reviewCell)
inside cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var section = indexPath.section
let cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as PhotoAndRateTableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
You're misusing the dequeue procedure:
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as? PhotoAndRateTableViewCell
if (cell == nil) {
cell = PhotoAndRateTableviewCell();
}
You want to reuse a cell if available, or create a new one if not. In your case, you're creating a cell every time (of the generic class) and then attempting to dequeue a cell from your custom class (which has never been created)
As far as preserving the data, you need to implement the prepareForReuse method in the table cell which should clear whatever index specific data was contained in the cell. Then in cellForRow you can re-set the data for the cell for re-appearance

Retrieve object from custom UITableViewCell on selection

So I have a UITableView populated with custom UITableViewCell. Every cell is loaded with an object i would like to retrieve upon row selection.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Here I would like to retrieve the object associated with the selected row.
// Object "cell" is inferred as a UITableViewCell, not as CustomTableViewCell :(
var cell = myTableView.cellForRowAtIndexPath(indexPath)
}
As described above, I can't access the CustomTableViewCell in order to get the associated object. Is there another way of doing this?
Usually, your UITableView is backed up by a data source, which is e.g. an array. Therefore, use the provided indexPath to get the object from the array.
Apart from that, you can also cast the cell to your custom class:
var cell = myTableView.cellForRowAtIndexPath(indexPath) as CustomTableViewCell
You should cast it to CustomTableViewCell, try that:
var cell = myTableView.cellForRowAtIndexPath(indexPath) as CustomTableViewCell
You have to type cast to the class which you have used when constructing the cell.
let cell = myTableView.cellForRowAtIndexPath(indexPath) as UITableViewCell
or
let cell = myTableView.cellForRowAtIndexPath(indexPath) as MyTableViewCellClass

Resources