Subclassing a UITableViewContoller subclass created using Storyboard - iphone

In my application, I thought it would be a good idea to create a subclass of UITableViewContoller (call it GenericTableViewContoller) which has a few prototype cells created in Storyboard that are reused throughout the app.
Now, what I wanted to do was to create a subclass of GenericTableViewContoller (say SpecialTableViewController) that has some other prototype cells created in Storyboard that are used only in SpecialTableViewController.
Thus, I have two scenes in my main storyboard, one for GenericTableViewContoller and one for SpecialTableViewController, each with their own set of prototype cells.
The problem I am running into, is that SpecialTableViewController gets nil prototype cells when I call dequeueReusableCellWithIdentifier: for a cell identifier declared in the GenericTableViewContoller scene. Cells declared in the SpecialTableViewController scene dequeue just fine.
Is this expected behavior (I have a strange suspicion it is)? Do I have to call registerNib:forCellReuseIdentifier: in SpecialTableViewController to actually get them registered from the other scene? Any simple way to get around this?

Is this expected behavior (I have a strange suspicion it is)?
Yeah, this is the expected behavior. The core concept here is that the storyboard is a object-instance designer, not a class designer. For example, you're free to make three scenes, each with the same view controller class, but all with different view layouts.
There isn't an simple way to share prototype table cell layouts between different table view instances short of putting them into their own XIB, and using -registerNib:forCellReuseIdentifier: and manual segues.

Related

Setting up Transitions/Segues from different elements of a Table View using Storyboards

I believe my question is relatively basic but I still haven't found something that directly answers it. I'm trying to learn Objective C and iOS Programming using Storyboards and am in the process of building my first app now. The way I have it set up right now is, I have a Navigation Controller that goes to a Table View controller (controller A). I'm passing an array to my table view and I have the disclosure indicators on the different elements in my array. I also have a second different view controller (controller B) with a table view in it. I want different elements of controller A to transition to different views/controllers etc. I'm familiar with the concept of segues and the prepareForsegue method however, I dont need prepareforsegue here since I'm not really passing anything to the next screen. I just want to be able to click different elements of my Table View in controller A to bring me different views (i.e like controller B and other views that I plan to build). Is there something I'm not seeing or do I need to fundamentally change my design?
Perhaps you're thinking of creating different prototyped cells?
Here's how I understand your question:
I have two (or more) different kinds of cells where I know the view to which they would transition beforehand (when your table queries the delegate).
I would like those cells to go to different controllers rather than the same controller.
If this is right, check it out:
Create a new UITableViewCell in the table by dragging from your kit
of UI objects.
Give each cell a reuse Identifier
Control+Click and drag to your target view controller
You'll get a popup asking what type of segue and what UI object triggers the segue
Then you'll see two segue indicators leaving your UITableViewController
Finally, make sure you dequeue the right type of cell:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"CellReuseIDA"];
return cell;

Custom Objects and Storyboards

Are Custom Objects (the little orange cubes) still supported when using storyboards?
Details: I was making a sample iOS App using storyboards and I added a custom object mapping a class which only had a button and a method for that button and I started getting strange errors. I removed this custom object and added the button and the method to the view controller class and everything worked as expected; this lead me to believe that something changed in the way custom objects worked when using storyboards, am I correct?
The orange cubes only instantiate objects at wake-up. They're not really meant to add views. For example I use a few orange cubes to instantiate extra UIViewControllers and then I link them to outlets in my parent UIViewController. This gives me a nice clean way to create a number of child UIViewControllers for the parent UIViewController. It was pretty much the same as pre-storyboard IB as well. If you wanted a view, the you would add the view. If you wanted an object you could instantiate it by IB or manually in the UIViewController.
Hope this helps.

Handling Memory with ARC when subclassing views

This is a curiosity question (unless it proves to have created a memory leak, then it's real). I have often created custom UITableViewCells for my projects before ARC, but this is the first time I've had an opportunity with ARC and Storyboards. It's written often that the best practice with ARC when dealing with IB assigned views (UITextField, UIImage, etc.) that property that holds the reference be set to "nil" in the viewDidUnload override in the UIViewController.
My question in this case is concerned when you subclass a UIView instead of a UIViewController. For example the UITableViewCell. I have set up a Custom table view cell in my prototypes and added some control views to it. I then created a subclass of UITableViewCell and assigned it to the prototype for IB to return when it dequeues. I created some IBOutlets and linked the control views to these IBOutlets. All fairly typical stuff. My question is that since I don't have anything to set the IBOutlets to nil, have I created a memory leak?
Thanks for any advice.
Only you can know if you have created a memory leak because it depends how you have your structure, however you probably havent. In arc it is much harder to create a memory leak since the retain release is handled by you.
But here is what you need to know.
First of all, setting things to nil in the view did unload method is only necessary to set in a view controller, but this is only because that view controller might be holding STRONG reference to certain elements in a view. Remember that in ARC objects are released when there are no strong references to them. When you add an element to a view using the IB this view has a strong reference to the element. If you additionally create a STRONG property in the viewcontroller to this element now you have 2 things pointing the element. If there is a low memory condition and the system wants to free up some memory (releasing non visible views) that is when the viewdidunload is called (to nil possible strong reference to elements in the view and to nil other objects that were for that view but can be easily recreated)
Your concern might be in hooking up stuff to the IB on the UITableViewCell. As long as you hook up these controlls to the prototype cell that you designed then it is perfectly fine. Remember that this prototype is a container for all your controls in that cell so the table should be managing the memory for these (when not needed everything in that cell will be unloaded or reused)
Important: You should hook up the controls to the table view cell, not
to the view controller! You see, whenever your data source asks the
table view for a new cell with dequeueReusableCellWithIdentifier, the
table view doesn’t give you the actual prototype cell but a copy (or
one of the previous cells is recycled if possible). This means there
will be more than one instance of PlayerCell at any given time. If you
were to connect a label from the cell to an outlet on the view
controller, then sev- eral copies of the label will try to use the
same outlet. That’s just asking for trouble. (On the other hand,
connecting the prototype cell to actions on the view controller is
perfectly fine. You would do that if you had custom buttons or other
UIControls on your cell.)
raywenderlich.com Page 149
iOS5 by Tutorials Beginning Storyboards

iOS5 Storyboard: Reuse Custom UITableViewCell in multiple UITableViewControllers

Using a dynamic, custom cell prototype that I design in, say, UITableViewController A (in Interface Builder/Storyboard), works really well with dequeuing the cell (through its identifier, cellA) and such in cellForRow... I use a custom class (UITableViewCell subclass, let's name it MyCustomCell) to link up the labels and image thumb and it works all pretty well and straight forward in my UITableViewController A.
Now I create a UITableViewController B (in Storyboard), which happens to have the exact same design/functionality for its custom cells (dynamic cells). So I switch the class of these cells to the MyCustomCell and give it a new identifier, cellB.
In UITableViewController B, I dequeue the cell in cellForRow... and use the new identifier cellB. Note: Using cellA here leads to a crash, more or less obviously.
But when the table view shows up, while running the app, the UITableViewController A works just fine, and the almost identical UITableViewController B does not work (empty cells).
In Storyboard, it looks sort of off a bit, because the custom cell is designable within the UITableViewController A but in UITableViewController B, it's just a simple, plain cell. Despite the class associated to MyCustomCell.
How would one avoid copy&pasting these cells to the other controller (and therefore heavily going back and forth between copies when making design changes) – and rather just properly re-use it?
What you are doing is correct. I don't know why its not working, it may be some problem with reloading the tableview; check with your datasource and the datasource method.
- (NSInteger) tableView:(UITableView *) tableView numberOfRowsInSection:(NSInteger) section
rather what you can do is: drag a
Viewcontroller
and then drag a
tableview
and make it dynamic and do the thing that you did earlier; it worked fine for me when I did so myself.
Saying the Cell is from a your custom class doesn't mean it's "designed" the same. What you really try to achieve here (and what I'm looking for) is some king of "Contained" Cell, but this is only doable with a ContainerViewController in iOS 6 I think. The other option is to use a XIB for that one Cell — that should work just as good, but then you lose the benefits of having an overview in the Storyboard.
I had a similar problem, I had created a custom cell with a uitextfield inside it. It was working well in the first tableview but not in the second. I figured out that the textfield's delegate was not connected to the custom cell. I connected the two in storyboard by making a connection from textfields delegate outlet back to the textfield.

reuse view from storyboard

I have a tableview with custom section headers. The view for the section header is defined in the storyboard and wired to an instance variable. Is there a way to request a new instance of the view from the storyboard?
In the past I have done this by having the section header defined in its own xib file and getting a new instance by using
[[NSBundle mainBundle] loadNibNamed:#"TimerViewSectionHeader" owner:self options:nil];
UIView *newHeaderView = self.sectionHeaderView;
I dont' think there is a way to do that. Best bet is to put the tableview custom header view in a separate nib and load it like you did in your code sample whenever you need to use it.
I tried to do the same thing and ran into the same problem.
I like to work with storyboards a lot and was impressed how fast I could create a working UI. However, as soon as you need to re-use views it makes a lot of sense to put those into a separate nib along with its UIViewController subclass.
You can then place a generic UIView in all the places where your re-used view should go and add the view using your ViewController:
[myReusableViewController loadView];
[myReusableViewController viewDidLoad]; // You have to handle view callbacks yourself.
[self.myReusableViewPlaceholder addSubview:myResusableViewController.view];
[myReusableViewController viewWillAppear:YES];
So to sum it up:
Use storyboard, it's great
Create the scaffold of your application in the storyboard, along with any static view (like About screens etc.)
Create re-used views in a custom nib + UIViewController subclass and add UIView placeholders in your storyboard.
In another answer I thought about some Pros and Cons of Storyboard
The solution I've come up with for this is as follows:
I have a tableview with multiple prototype cells that displays complex data. There is a segue to a detail view, and a transaction process view.
This first tableview has a search button that displays a new tableview with the results. It needs the same functionality as the main tableview that pushes it; including segues to the detail and transaction progress views so:
On storyboard, select and copy your main tableview. Deselect and paste. Create a push segue from your main tableview to your 2nd tableview; or from where ever you want to navigate to it from. Modify the 2nd tableview as you like. IE: If it requires some UI changes no problem.
Create a new viewcontroller class that is a subclass of the viewcontroller running the main tableview.
Override the data delegate in your subclass to serve up the subset of data you want.
Back in the storyboard, select your 2nd tableview controller and in the identity inspector select your subclass as the custom class.
For this solution to work smoothly, your app really needs to be managing data for the views. You could use prepareforsegue to pass data from 1st tableview to the second, but I've found the app data model far more flexible from numerous points of view.
Unless you have buttons that push to the sub views via segue, your subclass will need to override functions that push via segues with identities. NB Segues must have unique identifiers if you id them at all.
It took a lot of trial and error to figure this out, but once you understand the concept, it's a relatively smooth solution that is quite adaptable and not so bad to implement.
I am not sure about just views, but the way that I was able to get view controllers out of my storyboard is as follows.
UIViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IdentifierName"];
From here, perhaps you might be able to use this similarly to how it was once done with nibs.
I've been able to reuse a view in the storyboard just by connecting a transition from one tableview into the one I want to reuse.
so my tableview that I want to reuse is pointed to twice.
It sort of works but the problem I'm running into it setting a variable (using instantiateViewControllerWithIdentifier) in my app delegate to my table view that is getting reused.
It seems that if I reuse it, the storyboard is creating 2 instances of my tableview and the one I get with instantiateViewControllerWithIdentifier isn't the one I want.
I'm not really sure if this is the proper way to do it. But I assume many others are doing this somehow. With the custom table cells in storyboard I suspect lots of people want to reuse their views.
For example: We want to reuse the view(include subviews) in storyboard shown below.
The best solution I know so far is clip and paste the view related code to the New Singe View file without losing the information.
Detailed steps are as follows
Step 1: Rename the view we want reuse. Just prepare for step 2.
Step 2: Open storyboard as source code in order to clip the XML code we need
Step 3、4: Search and clip the code we need
Step 4.5(Not needed): Open as Interface Builder to see the view removed
Step 5、6: New XXX.xib and paste the code we clipped just now
Step 7: Important. Insert code<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> to XXX.xib source code.
Warning: Do this before open it as Interface Builder! Otherwise, you will see wrong size and layout waring.
[![step 7][9]][9]
Step 8: New XXX.swift to connect the XXX.xib
[![step 8][10]][10]
Step 9: Add the view anywhere we want
[![step 9][11]][11]
I get warning: "You need at least 10 reputation to post more than 8 links."
Can you support me to upload the remaining 3 screenshots?