How to make a super class of custom UITableViewCell? - ios

I am creating a UITableView which has multiple types of cells.So I creating multiple cell using xib and for each cell I have one .h file one .m file and one .xib file.All these cells has some common things like cell background color,property(UILabel,UIView) and actions(UIButton click).
So I am doing a set of common things again and again.So how can I create a super class of these cell so that I can come out of the problem.I should be linked the custom xib cell to my super class.
Edit 1.0 :-
Suppose I have created a Super Cell subclass of UITableViewCell having the all the common properties of those cells in its header file (SuperCell.h) and also implemented all the common actions in its implementation file (SuperCell.m).Then I Made all those .xib cell header file as a subclass of my SuperCell. Now how can linke these .xib files header property to the SuperCell header property which is same.
Edit 2.0 :-
Thanks #Fogmeister for pointing me out that it will be a big hierarchies and difficult to maintain.And If I want to add some new label in child cell then I am also not clear where should I add and how to linked with the super cell.
Let me clear my question explaining my project a little bit.
I am creating an social app like facebook which has Text post,single image post,double images post,multiple images post, poll,event,etc.
So for my social app landing page I have a UITableview controller and all these type of post is linked to one one cells.All these cell has some common things like Post ownername(UILabel),#handler (UILabel),profile pic ( ImageView) ,Post time (UILabel),like button (UIButton),comment button (UIbutton) etc.
I have done everything and it is working fine.I have written a lot of common code for setting up all these cell as there is not SuperCell of these cells.So I am trying to figure out a solution to make it little bit easier.
Thanks

Ah, I see your problem now. As a very first starting point I can think of two possible (maybe three) ways of approaching your issue.
(N.B. everything here is just me using the Facebook app as an example, your actual app may differ).
At the moment you have different cells StatusCell, PhotoCell, VideoCell, ShareCell, etc...
Each of these have various different elements... userNameLabel, userAvatarImage, timeLabel, likeButton, commentButton.
Then each has a "contentArea" that contains the status, photo, video, url, etc...
First solution - Component views
The first approach I was thinking is to keep your different cell types but then to create UIView subclasses to easily populate the areas. So instead of the cells having the different user labels and images etc... create a view called UserDetailsView.
This UserDetailsView will take a single property of a User object. It then uses this object to populate the different labels it contains such as userNameLabel, userAvatar etc...
Now you can just add this view to each different cell type.
You can also create components for the ShareView which might include likes, comments, etc...
Second solution - Generic cells
In addition to creating these different components for each different type of Cell you could actually use a single type of cell. (This would only work if the content is in roughly the same place for each).
So the additional part to create now are the different content views. This might be a StatusView, PhotoView, etc...
Now you can use one generic cell type that has a space for a content view. (Maybe placed inside a container view for positioning and constraints).
Third solution - React Native
What Facebook does for their timeline is to use the React Native framework that they have created for immutable view hierarchies. This is a more complex method as it requires reworking the way you build stuff but definitely one to keep in mind for the future.
https://facebook.github.io/react-native/

create your "parent cell":
#interface SuperCell : UITableViewCell
#end
#implementation SuperCell
// background logic and all the stuff that is equal for your child cells
#end
with it's .h and .m files.
then create your "child cells" (with their .h and .m files) and make them inherit from your "parent cell":
#interface SomeCustomCell : SuperCell
#end
#interface AnotherCustomCell : SuperCell
#end
and so on...

Related

How to design a ViewController with complex TableView

Imagine this scenario:
I've 10 different and custom UITableViewCell: one with a textfield,
one with a button, one with some labels, one with a textview, one
with an imageView and so on.
I've a ViewController with a tableView where I wanna display these cells.
The number of cell displayed can vary based on some conditions (and also the height, the background color and other parameters)
The user can interact with these cells
What is the best way to design this in respect of the MVC and maintain the ViewController lightweight and maintainable as possible?
How to take advantage of Swift language in doing this?
Is there any famous and consolidate design pattern to apply?
i will try to share some of my experience:
Create separate custom UITableViewCelll as per requirement like : textfield, textview, imageview, label etc. this class must not dependent on data calculation it is only for cosmetics UI. that means there must not be any method like updateCellWithData:(someDATAObj). This logic must go in some cetegory as discussed below.
Register separate custom UITableViewCelll with your tableview.
Create separate class (NSObject) as datasource and delegate for your UITableView.
Use category to populate data in your custom UITableView Cell. some thing like updateCellWithData:(someDATAObj).
Use constant file for your constants like height for tableView Cell, reuse identifier names, notification name.
try with some code atleast, then we can help you with best.

How to recreate UITableViewController with static cells support?

I have a lot of common logic, therefore all my viewControllers inherit from BaseViewController, BaseDetailsViewController or BaseWebViewController. The last two inherit from BaseViewController which inherits from UIViewController. The problem is I cannot use tableViews with static cells because my BaseDetailsViewController is not inheriting from UITableViewController.
I'v never used and inherited UITableViewController because the same could be achieved by inheriting from UIViewController, wiring it with an added UITableView and having implemented datasource and delegate methods. Therefore for the form type screens (SignUp or other data input screens), I use my own BaseDetailsViewController which adds nice and handy methods (input validation, custom styling, scrolling keyboard, handles input field navigation and etc.)
Using UITableViewController has two real benefits: 1) keyboard scrolling (if you use text fields) and 2) easy creation of your form UI elements inside on screen. The first benefit is irrelevant for me, because I'v already have my own implementation of this stuff inside BaseDetailsViewController. Regarding the second benefit, I'm creating my form inside scrollView which gives a lot of flexibility but it's a little bit more effort (especially when need to update the screen). Therefore I heard some guys implemented their own UITableViewController and then made it to inherit from their BaseViewController. Therefore I started to dig into this approach.
So far I'v came upon these two approaches:
Recreate your own tableVC. Not clear how to make it work for static cells. Currently my demo app crashes if my ReplaceTableViewController is not implementing numberOfRows and cellForRow, and not shows static cells if I implement them with dummy content.
method-swizzling. Not clear how to change class inheritance by injecting baseViewController inheritance for UITableViewController, thought still not clear which methods are needed to be added.
Anybody tried and want to share?
UPDATE I'm not using storyboards as I promote clean MVC - every screen as component should have its own Model, View (Xib), and controller, all stored in separate files to eliminate merge conflicts of multiple devs in large app projects (30+ screens). And therefore container view with embedded segue to tableViewController is also not an option.
UPDATE2 In case anybody would like to take a look why and how I'm doing this, here's a link to my open source template based new project generator framework which I started to publish recently.
Static cells need a UITableViewController. You can't changed this right now.
But to use static cells in a UITableView outside of a UITableViewController you can use a ContainerView in your Non-Table-UIViewController, where you place a real, separate created UITableViewController working with those static cells.
To share common code between multiple view controllers, inheritance is not that best solution as you found out by yourself while subclassing UIViewController vs. UITableViewController. You can use some sort of composition for sharing code or - especially for objective-c - categories.
Categories are not allowed to have its own properties, but there are workarounds possible with objc_setAssociatedObject.
Another approach would be to not use static cells, but dynamic cells in a UITableView with DataSource-Delegate :)
As you see in my screenshot, to reuse a special TableView with static cells, i place it in other ViewControllers in a ContainerView. Since you are not using storyboards, i am pretty sure that this can also be done by code without storyboard.

Setting up a UITableView with multiple rows containing different child views

As a small disclaimer, I'm pretty new to iOS Dev and have mainly worked with Appcelerator Titanium in the past, so this may be pretty basic.
Currently I'm in the middle of trying to create a page in an iPhone app that pulls data from an external API. That API returns a JSON array of objects that I'm using to populate a table (pretty standard behavior).
Each hash in the array contains of squares that I need to display in the table view and thy are formatted different based on the number of squares. For example:
If one comes back the table view cell contains a name and a single large square.
If two come back the table view cell contains a name two slightly smaller squares positioned overlapping.
If three come back the table view cell contains a name three slightly smaller squares positioned shaped like a triangle.
If four come back the table view cell contains a name four slightly smaller squares positioned in the shape of a square.
If more than for come back the table view cell contains a name, four slightly smaller squares and the last square has a +x count for how many there are in addition to the first 3.
Note: The name is in the exact same place on each cell.
So the real question is it seems like I'm not sure which of these two options are the best way to go:
Create 5 different SpecificCell.xib files (along with .h and .m files) and in cellForRowAtIndexPath create one of those and return it. This seems like a LOT of duplicate code for name, etc. and in general just a ton of code (15 new files) for something that realistically only changes a part of the cell (Name remains in the exact same spot, only the square images change).
Create a single Cell.xib (along with .h and .m files) and pass the dict to a new function that returns a parent view and the child square views, then add those to the cell in cellForRowAtIndexPath.
My main concern, and I'm curious what actual Objective-C developers tell me here haha, is do I receive memory benefits from using the first approach because the app already knows in memory how to create a cell with those exact views?
Or, is there a third way I don't know yet?
Your analysis of the issue is correct, and if this is as small as you describe there shouldn't be a performance penalty either way. Both of these are correct, but you have more options:
Create a class for each cell (and new xib), but combine them in one file. It's only by convention and Xcode's "new file" windows that each class always gets its own file. TableViewCells.h (TableViewCells.m is optional if you're just adding IB outlets). Then in this file:
#interface OneImageCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *firstImage;
#end
#interface TwoImageCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *firstImage;
#property (weak, nonatomic) IBOutlet UIImageView *secondImage;
#end
Easy to forget this creates the class, not the file in the list. Probably not necessary in this case, but good to know if you do find yourself needing many tiny subclasses and don't want to clutter the file list. Swift actually does away with the convention of one class means two files, good riddance.
Create new .xibs for each cell, but one combined class file and switch dynamically. Long the trick for combined code used iPhone/iPad apps, I find it it's a bit cumbersome to set up and manage. Useful if you're creating prototype cells in a tableView in IB, since you don't have to write the code, just set the class of the cells to be the same and reuseIdentifiers to be different.
Use the same xib .h and .m, but use different reuse identifiers. The reuse identifier fulfills its purpose here. Regardless of the same class and xib, if using different reuse identifiers then they will go into the same pool, saving setup work when reused. In -cellForRowAtIndexPath setup and use the kind of cell you need, and you could set a flag as a property of the cell to confirm setup work has already been done, saving that work.
Of these, 2 with IB is probably the simplest and most Apple-y, which is usually the way to go. All would be fine, including your two -- save work when you can, but again, even doing light-to-moderate setup in -cellForRowAtIndexPath is usually fine.

How can I customize instances of a template xib

I'm learning about xib files and just starting to understand why people use them as well as or instead of storyboards. My question is about how and when it's appropriate to use the xib as a "template".
Let's say I have a xib mapped to my custom UIView subclass - I know how to set that up in IB - and my xib has a UILabel subview. This is a very simplified example just for the purposes of the question, but basically I'm trying to create a view that can be reused for each screen of an iOS "introduction" walkthru, like the panels of https://github.com/MatthewYork/MYBlurIntroductionView
So I want to set most of what's in the view up at design time, and most of it will be common to each instance. The text I want to put in the UILabel is going to be static (i.e. I know it now at design-time) but each instance of the view will have different text. So let's say that I want to position the UILabel in different places in each instance, depending on how much text is in it etc and whether it's covering something else important. Now, I know I could do this programmatically, i.e. have the label as a #property linked up in IB and then set frame position in the code, but as far as I understand it the beauty of using xibs is that you can do known things like this at design-time.
As far as I can see my options are:
Load new instances of the xib and set the position etc programmatically as mentioned above (would rather not if possible)
Create my template xib, setting all the common stuff, and then make copies of it "CustomView1.xib", "CustomView2.xib", etc. (a bit yuck but not too bad)
After creating my template xib, use the storyboard to drag in new UIViews and somehow set each to be linked to my one "CustomView.xib", and then somehow do my static repositioning of the subview UILabel within each of those UIView instances on the storyboard. Is that possible? If so that'd be great. Obviously I know I can set each of those UIViews to be instances of my UIView subclass, but I'm just missing the link between doing that and customising each instance. Does the file's owner have something to do with it?

Location of UITableViewController files

I have multiple tableviews that have various static cells and everything is cool.
I would like to implement some functionality to a button that is in one of the cells in all of the tables, but I do not know where the header and implementation files for UITableViewController are located and or how to access them. Any ideas?
You can't directly manipulate UITableViewController. Besides, it is not a good idea to do it anyway. The best way to do it is subclassing it.
Command+N and create a new NSObject file
When prompted, name it whatever you like (e.g. MyTableViewController)
Click on MyTableViewController.h in left side pane, and change NSObject to UITableViewController.
Goto the XIB file or the Storyboard (whichever you are using) and change the class of your UITableViewController to MyTableViewController.
Give a number to the button's tag field (e.g. 1001).
Now, in your MyTableViewController.m class, get a hold of the cell (cellAtIndexPath:) and then get a hold of that button with tag ([cell.contentView viewWithTag:]).

Resources