UITableView just for GUI controls, no DataSource - ios

I'm about to write an iOS app in Swift. The main View Controller is a UISplitViewController. The master view of it is a navigation controller whose root view controller is a UITableViewController.
The cells in this TableView should only contain GUI elements (UIButton, UISwitch, UITextField etc.). There are quite a few of them so that I want to make use of the scrolling feature of the TableView and want to design a few custom Prototype Cells.
However, I'm still a learner of Swift, Cocoa Touch and all that. I know that a TableView needs a DataSource (and a Delegate) but because I don't have data to display in my cells ... how would my cellForRowAtIndex function look like? How would I even create a few "constant" cells (of prototype 1, prototype 2, ...) in the TableView? I guess it's not possible at design time in IB but only by code? How so?
Thanks so much in advance!

Setting your tableView delegate in your viewController class is mandatory to override those methods.
You can use numberOfRowsInSection to return a constant value that will be your number of rows.
Inside your cellForRowAt you can verify which row are you in and call appropriated cell.
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
//call cell type 1
}
}
Here you have a reference to create custom cells using xib and call it into your table.
Custom UITableViewCell from nib in Swift

Related

StoryBoard actions cannot be targeted at repeating content [duplicate]

I have just created an app and have started hooking up #IBOutlet's to the storyboard. I am connecting some of them to labels in a UITableViewCell Prototype Cell with a Basic Style. When I connect it though I get this error in the Storyboard:
The detailText Outlet from the TableViewController to the UILabel is invalid. Outlets cannot be connected to repeating content.
Can someone help me out? I have set it up the way I always do successfully but this time it has chucked me this error.
Create a table view cell subclass and set it as the class of the prototype. Add the outlets to that class and connect them. Now when you configure the cell you can access the outlets.
There are two types of table views cells provided to you through the storyboard, they are Dynamic Prototypes and Static Cells
1. Dynamic Prototypes
From the name, this type of cell is generated dynamically. They are controlled through your code, not the storyboard. With help of table view's delegate and data source, you can specify the number of cells, heights of cells, prototype of cells programmatically.
When you drag a cell to your table view, you are declaring a prototype of cells. You can then create any amount of cells base on this prototype and add them to the table view through cellForRow method, programmatically. The advantage of this is that you only need to define 1 prototype instead of creating each and every cell with all views added to them by yourself (See static cell).
So in this case, you cannot connect UI elements on cell prototype to your view controller. You will have only one view controller object initiated, but you may have many cell objects initiated and added to your table view. It doesn't make sense to connect cell prototype to view controller because you cannot control multiple cells with one view controller connection. And you will get an error if you do so.
To fix this problem, you need to connect your prototype label to a UITableViewCell object. A UITableViewCell is also a prototype of cells and you can initiate as many cell objects as you want, each of them is then connected to a view that is generated from your storyboard table cell prototype.
Finally, in your cellForRow method, create the custom cell from the UITableViewCell class, and do fun stuff with the label
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellIdentifier") as! YourCell
cell.label.text = "it works!"
return cell
}
2. Static Cells
On the other hand, static cells are indeed configured though storyboard. You have to drag UI elements to each and every cell to create them. You will be controlling cell numbers, heights, etc from the storyboard. In this case, you will see a table view that is exactly the same from your phone compared with what you created from the storyboard. Static cells are more often used for setting page, which the cells do not change a lot.
To control UI elements for a static cell, you will indeed need to connect them directly to your view controller, and set them up.
If you're using a table view to display Settings and other options (like the built-in Settings app does), then you can set your Table View Content to Static Cells under the Attributes Inspector. Also, to do this, you must embedded your Table View in a UITableViewController instance.
Or you don't have to use IBOutlet to refer to the object in the view. You can give the Label in the tableViewCell a Tag value, for example set the Tag to 123 (this can be done by the attributes inspector). Then you can access the label by
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "someID", for: indexPath)
let label = cell.viewWithTag(123) as! UILabel //refer the label by Tag
switch indexPath.row {
case 0:
label.text = "Hello World!"
default:
label.text = "Default"
}
return cell
}
With me I have a UIViewcontroller, and into it I have a tableview with a custom cell on it. I map my outlet of UILabel into UItableviewcell to the UIViewController then got the error.
As most people have pointed out that subclassing UITableViewCell solves this issue.
But the reason this not allowed because the prototype cell(UITableViewCell) is defined by Apple and you cannot add any of your own outlets to it.
Sometimes Xcode could not control over correctly cell outlet connection.
Somehow my current cell’s label/button has connected another cell
I just remove those and error goes away.
For collectionView :
solution:
From viewcontroller, kindly remove the IBoutlet of colllectionviewcell
. the issue mentions the invalid of your IBOutlet. so remove all subclass which has multi-outlet(invalids) and reconnect it.
The answer is already mentioned in another question for collectionviewcell
Click on simulator ,
Navigate to Window and enable Device Bezels

Configuring UICollectionView to keep the same cell view

I have a collection view delegate
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath)
-> UICollectionViewCell {
}
I wanted the property of the cell to persist between each call to this method.
let cell = levelView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier,
forIndexPath: indexPath)
But retrieving cell using dequeueReusableCellWithReuseIdentifier seems to create a new cell view element that is different from the initial one.
cell.accessibilityIncrement()
So the cell accessibility value cannot persist after tapping on the cell.
I need to do this because I wanted to do UI testing by tapping on the cell.
Any help is appreciated!
Reusable cells in iOS are handled with a queue. This helps the tableViews and collectionViews move smoothly and remain efficient with a large amount of data. I don't think you would want to change the way that is designed to work in your application. This way, the device only needs to load as many cells into memory as can be displayed on a single screen. As cells move off the screen, they can be reused as another cell as cellForItemAtIndexPath will be called to load the required data into the reused cell.
If the goal is to have a value persisted between cell reloads, consider using a map or some other similar variable that could be managed by the collectionView's dataSource delegate.
For example, in your viewController that contains your dataSource delegate, you could have a Dictionary defined like so:
let numberOfTapsByIndexPath = [NSIndexPath: Int]()
Then every time a cell is tapped, you would increment the value in the map for the cell tapped. That code might look something like this:
let previousTaps = numberOfTapsByIndexPath[indexPath]
numberOfTapsByIndexPath[indexPath] = previousTaps + 1
I'm not 100% sure that was the goal you explained above, but regardless, you'll want to move any persistent information out of the cell and into a variable that the dataSource delegate or some other singleton can manage.
Hope this helps!

How to have a separate click even for each UITableViewCell

I have a UITableView using the prototype cells that generates a list. They all share the same Prototype cell as the data presented on them is the same, however the function that it should perform is not the same. All of these cells should be under the same section.
Should I use 6 different prototype cells and change which one I'm getting in the cellForRowAtIndexPath function based on the NSINdexPath#row, or is there a simpler way to register custom logic for when a cell becomes selected.
For example, lets say that my table view looks like this:
Show Data - When clicked displays a popup window
Goto Website - When clicked goes to the website
Open application - When clicked opens another application
Open view - When clicked opens another view
How would I handle that logic separately?
You can use didSelectRowAtIndexPath to get a touch event for each cell.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
// Show data
} else if indexPath.row == 1 {
// Go to website
}
/// etc
}
Be sure to have set your tableViews delegate and datasource to your viewController, and have your viewController setup for this like so:
class MyViewController: UITableViewDataSource, UITableViewDelegate {
}

how to implement UITableViewController with multiple prototype cell programmatically in swift

I have just started learning swift and i created a settings page as show in attached image using the StoryBoard. The reference link used is http://shrikar.com/xcode-6-tutorial-grouped-uitableview/
Same thing i want to do it programmatically i.e. i want to implement cellForRowAtIndexPath function which has different prototype cell as shown in below image.
If possible please give example with reference to given example UI.
Thanks
A great start for you would be this project created by Apple. It includes a variety of things and is a demo app by itself. This will give all the general info you need to start working with UITableView and UITableViewCell.
1.Create a view (XIB) files for each of the custom cells you wish to see in your tableView. Although you can layout design in code, I would advise you to start out with visual approach and see how goes, since you must be able operate freely with such things as Auto Layout, Constraints, Size Classes, etc.
2.Create a UIViewController with a single table view in it.
3.Create a Cocoa Touch Class file (.swift) for each of the cells (XIBs) you created in step 1. In these files you should reference the stuff you incluled in the cell (UILabels, UIImageViews, etc.). Don`t forget that the cells should have these same classes (open XIB files, third icon on the right panel)
4.Create a Cocoa Touch Class file (.swift) for the UIViewController you created in the storyboard. Reference (mouse drag) the tableView in this Cocoa Touch Class. Make sure that the UIViewController in the storyboard has this class set (Custom class field, same as for cells in step 3)
5.Refister nib for the cell in your ViewDidLoad method
tableView.registerNib(UINib(nibName: "topCell", bundle: nil), forCellReuseIdentifier: "topCell")
tableView.registerNib(UINib(nibName: "contentCell", bundle: nil), forCellReuseIdentifier: "contentCell")
tableView.rowHeight = UITableViewAutomaticDimension; //<--Calculates rows height
tableView.estimatedRowHeight = 44.0; // automatically (iOS 8+)
6.On your UIViewController with tableView, click the last button on the right panel and drag "data source" along with "data delegate" to the same view controller (yellow circular symbol).
7.Make sure that your Cocoa Touch class (created in step 4) conforms to the protocols UITableViewDataSource, UITableViewDelegate (by implementing the necessary methods)
class FeedVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
} // <-- your class for the UIViewController with tableView
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}
If your are not completly sure how to implement these required methods, you can look them up in the project I referenced in the beginning of my post.
Please look more into dequeuereusablecellwithidentifier. If you are using Storyboard, add UITableViewCells with reusableIdentifier.

My header view in UITableView is not added to the UIView Hierarchy

Using UITableView and NSFetchedResultsController I refresh and display the content of my table. At some point I hava a screen without header view. It should be instead of the space between cells.
When I debug View hierarchy I have the following info. Selected cell in UI View hierarchy is appriopriate to the selected cell in Debug View Hierarchy.
To create a header view I use following method:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let workday = workDayObjectForSection(section)
let cell = tableView.dequeueReusableCellWithIdentifier(PBOUserWorkDayCellIdentifier) as! PBOUserWorkDayTableViewCell
cell.configureCellWithWorkDay(workday)
return cell
}
You shouldn't get view for tableView header using dequeueReusableCellWithIdentifier method. From the documentation:
If a cell object is reusable you assign it a reuse identifier (an arbitrary string) in the storyboard. At runtime, the table view stores cell objects in an internal queue. When the table view asks the data source to configure a cell object for display, the data source can access the queued object by sending a dequeueReusableCellWithIdentifier: message to the table view, passing in a reuse identifier
That means when you return header as reuse cell, tableView might take it do display in another place as cell. Note that behavior of header is different than cell, it stays at the top while section is visible.
However, you may use same view for header but create it from xib, storyboard etc every time and do not assign any reuse identifier. And if you looking for some optimization, you can store them in some array and return cached values. But I would like to recommend not to use subclasses of UITableViewCell as table header views

Resources