Setting up a UITableView with multiple rows containing different child views - ios

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.

Related

Same IBOutlet from different storyboards?

I have multiple storyboards in my project, each having an almost identical view controller (only dimensions are different). The storyboard used depends on the device in use. What I want to do is have the equivalent element from each storyboard under the same IBOutlet. This way, whatever I do to an element in the storyboard being used, the same would be done for all other storyboards. This is instead of creating an IBOutlet for the same element in each different storyboard.
For example, we may have two buttons, one in each storyboard. They are meant to be the same button but in different sizes, I set this button's alpha to 0 at one point the in Swift file. How could I do this for both buttons under one name (the same IBOutlet)? I know this means doing something on a storyboard which isn't even being used and therefore not accessible on the device, and I'm not sure whether it'll spit up an error or not. Surely this is a way around this though, because there are apps which use multiple storyboards.
I could imagine possibly stating if (storyboard == xnamex) {execute code for specific storyboard}, but this would mean having multiple if statement with the whole code repeated for different storyboards, and having to create an IBOutlet for each element, which is unrealistic. How would I get around doing this?
Many thanks.
If it's exactly the same button except as you mention the size on it. You can just pull an outlet to the same name and they both will be contained in there. As mentioned [Multiple buttons connected buttons best practise you pull the outlets to the same place and then action to the same place as well. However. Sometimes the action can be tricky, if you get problem there, just create a new action with the exact same name and then remove it. It will still be connected to the same name.

Access child views in custom UITableViewCell

Background:
I am trying to create a table view with around 4 types of different cell layout.
At first, I considered using static table view to solve the issue since the number of rows are somewhat fixed (nor more than 10)
But, after some thinking, I decided that I don't really want to be tied up to the UITableViewController. Thus, I tried to implement it with dynamic table view.
Question:
After I create 4 prototype cells, I found out that I'll need to access the child views in cell (to update their value). But the only possible ways I know seem to be:
1. Create a subclass for each prototype cell, and create `IBOutlet` to the child views
2. Assign `tag` for each child view for later access
But I don't really like these two methods...
The first one is too cumbersome, and the tag in the 2nd solution does't seem to be very sepcific (access the child view by just some magic number..)
So, I would like to know:
Is there any better practice for implementing this kind of
tableview. (multiple cell prototypes, and fixed row numbers)
Is static table view a better way to do it? If yes, will there be
any limitations when I am tied up to UITableViewController?
For example, if I need more complex UI, and decide to add more views on to it, will UITableViewController be less flexible than UIViewController
Thank you so much!
If the cells are very similar but with different layouts they could share a common UITableViewCell subclass provided the class doesn't need to know the layout it is in just configure the available outlets.
If the code does need to be aware of the layout used then it is probably best to make them separate subclasses.
For Swift use is or as? to confirm the correct subclass for the cell (for Objective C it would be the isKindOfClass method).
1.You do need to subclass the UITableViewCell if you want to access his IBOutlets.
In order to distinguish between the cell just use isKindOfClass
2.It depends how different your cell are from one another. If they have slightly different structure you might want to consider lodging the elements in cellForRow. Try to take a look at the built in structure cause it might save you some subclassing.
These structures have built in parameters such as: image,text etc.
Their structure is more strict though
Theses are the available types:
UITableViewCellStyleDefault, // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
UITableViewCellStyleValue1, // Left aligned label on left and right aligned label on right with blue text (Used in Settings)
UITableViewCellStyleValue2, // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
UITableViewCellStyleSubtitle // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod).
I don't really understand why you want to use tags?

How to make a super class of custom UITableViewCell?

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...

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