How can I customize instances of a template xib - ios

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?

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.

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

MVC pattern controller responsibilities and best practice when presenting a view and transitioning through states

I am familiar with the concept of MVC in which we divide the concerns of modeling, presentation and processing of information. But when it comes to a real life example it gets hazy.
Lets take for example Apples UITableView. Say we have a coresponding controller which takes care of suplementing the table (the presented UIView is custom and just has a UITableView, exposed as a property, at the moment).
The UITableView has a property backgroundView which I want to use for displaying some info when there are no elements to display. The real question is where should it be suplemented?
Make a method in the custom view which creates the view and shows it (showEmptyTableInfoViewWithMessage:).
As in first example but just expose an UILabel as a property and make a simple hide/show method and work on the labels text property from the controller.
Create a custom UIView which will expose the UILabel. Alocate it and assign it to the backgroundView property in the controller.
Create a UIView with an UILabel rigt in the controller and assign it to the backgroundView.
As all of these examples will work I am wondering which one is the proper way (the best seperate of concerns / maintable way). I belive No. 4 is the worst but that is just my feeling at the moment.
Thank you in advance for any information on the best architectural design/approach.
A UIView should be responsible for hiding or showing its subviews and managing its subviews. It shouldn't be responsible for whether or not itself is visible. That's why it exposes the hidden property--so outsiders can do this.
I don't like any of your four options personally.
I'd go with one of these two:
The backgroundView will already have a view object there. We can just create a UILabel object and add it as a subview to the table view's default backgroundView and add the appropriate auto-layout constraints. This would probably best be done by subclassing UITableView, and if so, I wouldn't expose a UILabel property, but rather expose an NSString property whose setter simply sets the label's text, and whose getter returns this text. You may expose a few other methods perhaps for setting the label's font and a few other things.
Create a subclass of UIView, perhaps called UIBackgroundView. This would be a UIView with a UILabel (and whatever else setup you want on it). It shouldn't expose the label directly, but like before, it should instead expose properties that let you set the things about the label you might like to set and does it via proxy. Then you instantiate it with a factory method something like this:
vwBackground = [UIBackgroundView backgroundViewWithText:#"Hello World];
And then simply:
tableview.backgroundView = vwBackground;
Between the two options, which you use depends on what level of reusability you want.
Option one is probably slightly better, and it saves some coding after you've created the subclass, but obviously, you can only do this with table views. If you want to do the same with a UICollectionView, or a UIScrollView, or a UIImageView, or whatever you can find that has a backgroundView property, you'd have to create similar subclasses for each... but in the end, it'd be easier and more intuitive to use, I feel.
But with option two, you can then automatically use your UIBackgroundView anywhere. It's just a UIView with a label, and you can do with it anything you'd do with any other UIView object.

IOS Storyboard: Load Multiple Subviews for given position

I have 3 different subviews all defined directly in the storyboard, so they have outlets to them as well. All of these subviews are meant to occupy the same coordinates on a screen at different times, with only one occupying the space at any time, so that it looks like some appearance is changing. How do I go about doing this? Say I also have a enumeration that defines what state I'm currently in and thus what subview is shown for that location.
Two basic options:
Just go ahead and add the three subviews to your scene. If you do this, there are a couple of tricks that will make your life much easier in IB:
For each of the views, go to the "identity inspector" tab (the third one) in the far right panel, expand the "Document" section, and give each of the three views unique "labels" (not to be confused with UILabel controls; this is just a label or description that IB will use internally to refer to your view). That way, as you navigate the tree of controls listed in the "Document Outline" (that list of all of your scenes that appears in the left side of the center panel), you'll be able to figure out which is which. As you work with these overlapping views, a strong command of this "document outline" will make your life much easier.
When you have the three views on the scene, you may find that it will be easiest to drag the view you want to work on to the end of the list of the three views (but at the same level as its peers) in that "Document Outline". You can then edit that subview. Repeat that process for the three subviews as you do your IB work on them.
You can make an outlet collection for your three subviews, if you want. This makes it easier when you want to perform some action on all of the subviews. Perhaps not of great utility when dealing with only three, but if you ever had more subviews, the collections can be useful.
You can define unique UIView subclasses for each of the three views, which can be useful to keep your list of IBOutlet references a little more structured. Also any view-specific UI logic can be isolated into the individual UIView subviews.
If you use this technique, if you plan on animating the transition between these three subviews, it's actually quite useful to not just put these three subviews on the top-level view of the scene in question. It's quite useful to have a view on the scene that defines the dimensions of the three subviews, and then put your three subviews inside this new interim subview. This way, when you animate changes, you can constrain the animation to just that portion of the screen. This new, interim UIView is often called a container view, but should not be confused with the iOS 6 container view that you'll see in IB, which is related to the next technique, defined below.
While all of those tricks can make the manipulation and management of the three sets of overlapping views in a single scene a little easier, I actually think that a custom container view controller is the best way to go. One scene for the parent scene/view controller, and a separate view controller and IB scene for each of the three different child views. It takes a little extra code up front (not hard, but a little alien the first time you do it), but then your code and the IB scenes are nicely isolated. Architecturally, this is the most elegant approach, IMHO. If you want to do this, you should refer to:
WWDC 2011 #102 on UIViewController Containment (Apple developer ID required)
the containment section of the View Controller Programming Guide
the containment section of the UIViewController Reference document

How could I clone/duplicate some sort of UIView for iOS?

(screenshot below helps explain what I am trying to do)
The idea behind this is that I have a UIView, with various different UI elements inside, for example, let's say I have a UIView, and inside there we have a UILabel.
Now I'm wanting to duplicate the UIView (with the label inside) BUT somehow after that I need to perhaps make a change to the label, e.g. change the text property.
The reason I need something like this is so I can structure the UIView with everything I need in it looking nice, but to actually have different data with different copies of it.
I'm not certain this is the best approach, but it's the only one I could come up with. If anyone has any ideas on how to do this, or any ideas on a better approach I'd really appreciate it. A lot!
I personally think the best answer is to create each view separately and configure it as needed. You can make a method that just configures new UIViews to look the same, and pass each view through it.
However, if you really need to copy a UIView, you can archive it, and then unarchive it:
id copyOfView =
[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:originalView]];
UIView *myView = (UIView *)copyOfView;
[self.view addSubview:myView];
If you have a bunch of these, make sure you're using the Instruments time profiler to check your drawing efficiency.
This is a very natural and useful thing to do. What you're looking for is a container view controller. Put your reusable "cell" into its own view controller and its own nib file. Then, in your parent view controller, use addChildViewController: to add as many of these as you'd like and configure each of them. They can each have their own IBOutlets that you can use to modify the contents.
This is very similar to the pattern used by UITableView and UITableViewCell (it doesn't use "child view controllers" specifically, but it does use this pattern).
For full details, see "Creating Custom Container View Controllers" in the View Controller Programming Guide for iOS.
Note that Storyboard includes a "Container View" as an option in the object templates to make this even easier.
If you want lower-level access, you can also do this by hand using UINib to load the nib file and wire its outlets (and this is how we used to do it before iOS 5), but today I would use child view controllers.
If you have only one label inside it the obvious solution is to have a custom UIView subclass with that label added as a subview. Everytime you need a new view you make an instance of your custom subclass and set the label text. If you have multiple things to set, some of which are common to all your custom subclass views you can use the prototype design pattern, it's pretty straight forward to implement.

Resources