iOS / Xcode 4: View won't load - iphone

This is really frustrating as I've tinkered with previous versions of Xcode and have done this before but playing around with a new app now, it's not working for some reason.
I have the app open to a UITableView and want it to load to a detail UIView once I select a cell. However, when I choose a cell in the iPhone simulator, it just highlights the cell blue and doesn't load the view.
Here is the code I'm using the the RootViewController:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WorkoutViewController *workoutViewController;
workoutViewController = [[WorkoutViewController alloc] initWithNibName:#"WorkoutViewController" bundle:nil];
workoutViewController.workoutName = [workouts objectAtIndex:indexPath.row];
[self.navigationController pushViewController:workoutViewController animated:YES];
[workoutViewController release];
workoutViewController = nil;
I have the view linked to the File Owner in the WorkoutViewController.xib file. When I put in a breakpoint at #implementation WorkoutViewController, it does get to that breakpoint but it goes to the #synthesize line and then jumps right back out to [self.navigationController ...etc]; and never returns back to the WorkoutViewController.m file.

I would guess that you didn't set the ViewController to be the TableView's delegate. To check, open your ViewController xib-file and rightclick FilesOwner. Under Referencing Outlet you would usually have both delegate and data source" connected to your TableView. If that is not the case, drag New Referencing Outlet to your TableView.
If I'm wrong and they are all connected, you might want put a breakpoint at the beginning of your didSelectRowAtIndexPath method. Does the debugger stop there, once you select a row?
It might also be worth mentioning that a breakpoint at #implementation usually doesn't make much sense, you would rather want to place it in a method like init. Also, even though you are using Xcode 4 now, this is unlikely to be the cause of your problem, it looks more like an implementation issue.
Hope this helps, if you need further help just let me know!

Doh! Problem resolved. I had forgotten to actually put the RootViewController into a navigation controller on the MainWindow.xib. Appreciate the responses.

Related

Attached a new controller to existing storyboard

I'm doing some iPhone development, and I'm using Storyboards to mock up and expedite my development.
I didn't came from the conventional way of doing things, do I have to?
Anyway, I have storyboard,
TableViewController
NavigationController->ViewController->TabViewController [
AnotherViewController
I wanted to add a new ViewController attached to the TableViewController so that when I click on the row item it will show it on the other view, however;
I can't find a way how to connect the new ViewController into the TableViewController (vice versa)
So I tried the conventional way of doing things on the
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I put the ff:
CViewController *controller = [[CViewController alloc] initWithNibName:????? bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
I tried to give the Controller an identifier on the Attributes Inspector but does not work and is giving me the following crash stack:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/paulvincentong/Library/Application Support/iPhone Simulator/5.1/Applications/A1C369F8-9EAD-4794-8861-945C73F7FE0B/SyncProto.app> (loaded)' with name 'ControllerViewName'
If I remove the Identifier, I'll get a no NibName exception;
What should I do? I know it should just be the same as I was able to go as far as four levels of relating controllers, there might be something at the back of my head that is confusing me...
TIA,
try this in your cellForRow
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard"
bundle:nil];
ViewCont * view = (ViewCont *) [storyboard
instantiateViewControllerWithIdentifier:#"view"];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self view animated:YES completion:nil];
}
Make sure you have set your storyboard also in the project manager.
Are u using IB? There you can drag directly.
Otherwise in storyboards you don't use the push method you stated. You use performSegueWithIdentifier. Storyboards are about segues. You can segue directly or use target actions.
Again the strength of storyboards is in their visual representation. Use IB.
Otherwise you might also consider delegation (ESP for ipad).
After playing around... I found the suitable answer to my question;
My problem appears to be cause of
Confusion - a new programmer's dilemma.. tho the question is a common one, we can never really deviate if its really the same with those already existing and asked before only up until we tried it ourselves and found out that it really was.
The solution could vary from case to case; and for me I tried to do the ff:
Approach 1: (using the "instantiateViewControllerWithIdentifier") with a segue arrow
Create the view to be added
Position your mouse pointer to the Nib element source view controller you want to trigger the segue then hold control
Drag you mouse to the destination view controller
A popup will appear, choose your segue type (push, modal, custom) then automatically xcode will create the necessary connections
Select your destination view controller and on the Attribute Inspector there is a Collapsible group with Identifier field -> on this field you will put your custom identifier for the view
So the source code would look like;
ViewController *view = [self.storyboard instantiateViewControllerWithIdentifier:#"CustomViewName"];
[self.navigationController pushViewController:view animated:YES];
Approach 2: (using the "instantiateViewControllerWithIdentifier") without the segue arrow
Create the view to be added
Provide the new controller with the necessary identifier then you're good to go
Using the same source as defined above
However, using this approach will break your storyboard's consistency and why use this? (still something I have to find out), its not obvious when you start looking for the segue arrow that was never there, albeit it works.
This code will not work on the basis that I don't have a nib with a name ????,
CViewController *controller = [[CViewController alloc] initWithNibName:????? bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
and since its on a storyboard and assuming everything was done using the storyboard, then time to forget about the nibName because it will never happen..
Hope that this idea would help a few...
Learning is a thorough process yet its a very interesting thing to do...
Thanks.

Why my iOS tableview do not work

I am learning iOS programming and I had a problem with tableview.
By tapping a cell in tableview, I want my program change to another view,here is my code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
testViewController* controller=[[testViewController alloc] initWithNibName:#"testViewController" bundle:nil];
controller.imageView.image=[UIImage imageNamed:#"gyf.jpg"];
[self.navigationController pushViewController:controller animated:YES];
}
the view controlled by testViewController is super simple. There is only a image view in it.
But after I tap the cell, there was only a blank view on the screen without any image.
In debugging, after controller.imageView.image=[UIImage imageNamed:#"gyf.jpg"];,I found controller.imageview is nil.
Please tell me where is the problem and why this phenomenon happen,thank you very much
I use Xcode 4.3.3 and run the program on iPhone 5.1 simulator
(This answer assumes that your testViewController displays OK and is just not getting the image you want.)
When you create a new controller and push it, it's view hierarchy isn't loaded until it executes viewDidLoad:. You're trying to update its imageView before that happens. Try adding a UIImage property to testViewController, setting that property instead in this code, and then updating the imageView once all the views are valid in the new controller.

How to call a detail view from a table view within a Storyboard

I have following problem.
I have created a tab based Application with three Views and Viewcontroller.
FirstView(Start screen stuff), SecondView (Detailpage), ThirdView (Table for listing items).
(Connections from storyboard were set automatically).
In the third view a table is integrated and the content is displayed fine.
Now I would like to call the SecondView , when a row in the table is selected.
I also tried to add a forth View , outside the tabBar Controller, to get the Detailview, but this also did not help.
I have tried several tutorials and forum tips, but cannot get it working.
The class is set to the right ViewController, the identifier is set to detail.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
DetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
[self.navigationController pushViewController:detail animated:YES];
detail.label1.text = #"It is working";
}
When clicking on the row, it becomes blue, but nothing happens. No error Message , nothing.
Hope that you can help :-)
OK, I have tried to "optimize" my design.
Still have the tab based Views, but when clicking on a row in the table, a new (not linked in Storyboard) view should appear to display the details of the selected quote.
I have created a view in the storyboard and called it "detailzitat"
I have created a DetailViewController.h/m as UIViewcontroller class
I have set the custom class to DetailViewController
I import the DetailViewController.h in the ThirdViewController.h
I have modified the didSelectRowAtIndexPath method in ThirdViewController.h accordingly.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
DetailViewController *detailVC = [self.storyboard instantiateViewControllerWithIdentifier:#"detailzitat"];
[self.navigationController pushViewController:detailVC animated:YES];
}
and my DetailViewController.m looks like
#import "DetailViewController.h"
#implementation DetailViewController
#synthesize label1, labeltext;
- (void)viewDidLoad
{
[super viewDidLoad];
labeltext=#"JUHU";
label1.text=labeltext;
}
But again, nothing happens, besides the row gets blue.
I do not understand. If I am using this code in a Non-Storyboard project, it is working.
What am I doing wrong ? Is there any tutorial for this combination within Storyboards ? Have not found one for this approach yet.
Try to learn from the different tutorials on the web, but the biggest problem is, most ones are not for iOS5 and I am not so good to transfer then.
Hope to get some hints :-)
You might want to think about your design. If I am understanding your description correctly, the user will be on the third tab, tap on a row in a table, and then you will be switching them back to the second tab. A navigation controller might be a more natural, less confusing, choice there.
But in any case, something like this will work sometimes:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
DetailViewController *detailVC = [self.tabBarController.viewControllers objectAtIndex:1];
detailVC.label1.text = #"It is working"; // <- this will not work consistently!
self.tabBarController.selectedViewController = detailVC;
}
The problem with this is that while the user is on that third tab, it's possible that the second tab view controller's view is unloaded (due to memory pressure for example).
It's also possible the user went from tab 1 to tab 3 immediately and therefore the 2nd tab's view isn't even loaded yet at all. (To even test the above code you would have to select tab 2 and then tab 3.)
If the second tab's view hierarchy is not loaded, the label1 property will be nil, and so this will not work. A better strategy would be to create a new #property of type NSString* on the DetailViewController. And set that property instead of trying to set the label1 directly.
Then in your viewWillAppear: for the DetailViewController you can update your labels as needed. At that point of course you can be sure that label1 is loaded and connected to the correct UILabel.
I hope that helps.
I think problem is at self.navigationController. If your view is not inside the navigation controller this will not work. So what you do is create a new navigation controller object there and then use it to show your detail view.

ext_bad_access when trying to show a tableView

I'm having the following issue:
I have a tab-style app. Eacht tab has its own viewcontroller and xip. Within the first tab-view, I try to display a button which load a next view, showing a grouped tableView. Everything works as expected, the numberofSectionsInTableView is called, and then I get an ext_bad_access error.
I try to explain my setup:
First (by the click of a button), I load the nip of the view:
FiltersViewController *filtersViewController = [[FiltersViewController alloc] initWithNibName:#"Filters" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:filtersViewController animated:YES];
[filtersViewController release];
In the NIB, the File's-Owner is set to the FiltersViewController class. The view-outlet is connected to the tableView, which is of class UITableView. The TableView itself is sitting in the FiltersViewController object.
The FiltersViewController has the following interface:
#interface FiltersViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {}
The tableView's delegate and dataSource is connected to the File's-Owner. I implemented the required methods for table-setup...
What am I missing? I've read that ext_bad_access has to to with accessing pointers / objects that are no longer existing. I followed the basic rules for memory management, and cannot find an error in the code.
Help is really appreciated. pawi
Ha! I got it!
I got the tableView's delegate and dataSource connected to the TableViewController (of type FiltersViewController) instead to the File's-Owner...
This was lucky, it got me busy for over a day now. :-(
Cheerz!
You mean EXEC_BAD_ACCESS right?
It basically means you are trying to access an object which isn't there. like 15th object of an array which has only 10 objects for example.
Most probably you've done it in cellForRowAtIndexPath method where you're populating the table view cells.
try to set the break points any where that feel incomplete, such as u can set the break points on numberOfSection, build and debug it, so you know where u have to change..

UITableView issue when using separate delegate/dataSource

General Description:
To start with what works, I have a UITableView which has been placed onto an Xcode-generated view using Interface Builder. The view's File Owner is set to an Xcode-generated subclass of UIViewController. To this subclass I have added working implementations of numberOfSectionsInTableView: tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: and the Table View's dataSource and delegate are connected to this class via the File Owner in Interface Builder.
The above configuration works with no problems. The issue occurs when I want to move this Table View's dataSource and delegate-implementations out to a separate class, most likely because there are other controls on the View besides the Table View and I'd like to move the Table View-related code out to its own class. To accomplish this, I try the following:
Create a new subclass of UITableViewController in Xcode
Move the known-good implementations of numberOfSectionsInTableView:, tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: to the new subclass
Drag a UITableViewController to the top level of the existing XIB in InterfaceBuilder, delete the UIView/UITableView that are automatically created for this UITableViewController, then set the UITableViewController's class to match the new subclass
Remove the previously-working UITableView's existing dataSource and delegate connections and connect them to the new UITableViewController
When complete, I do not have a working UITableView. I end up with one of three outcomes which can seemingly happen at random:
When the UITableView loads, I get a runtime error indicating I am sending tableView:cellForRowAtIndexPath: to an object which does not recognize it
When the UITableView loads, the project breaks into the debugger without error
There is no error, but the UITableView does not appear
With some debugging and having created a basic project just to reproduce this issue, I am usually seeing the 3rd option above (no error but no visible table view). I added some NSLog calls and found that although numberOfSectionsInTableView: and numberOfRowsInSection: are both getting called, cellForRowAtIndexPath: is not. I am convinced I'm missing something really simple and was hoping the answer may be obvious to someone with more experience than I have. If this doesn't turn out to be an easy answer I would be happy to update with some code or a sample project. Thanks for your time!
Complete steps to reproduce:
Create a new iPhone OS, View-Based Application in Xcode and call it TableTest
Open TableTestViewController.xib in Interface Builder and drag a UITableView onto the provided view surface.
Connect the UITableView's dataSource and delegate-outlets to File's Owner, which should already represent the TableTestViewController-class. Save your changes
Back in Xcode, add the following code to TableTestViewController.m:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Returning num sections");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning num rows");
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Trying to return cell");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.text = #"Hello";
NSLog(#"Returning cell");
return cell;
}
Build and Go, and you should see the word Hello appear in the UITableView
Now to attempt to move this UITableView's logic out to a separate class, first create a new file in Xcode, choosing UITableViewController subclass and calling the class TableTestTableViewController
Remove the above code snippet from TableTestViewController.m and place it into TableTestTableViewController.m, replacing the default implementation of these three methods with ours.
Back in Interface Builder within the same TableTestViewController.xib-file, drag a UITableViewController into the main IB window and delete the new UITableView object that automatically came with it
Set the class for this new UITableViewController to TableTestTableViewController
Remove the dataSource and delegate bindings from the existing, previously-working UITableView and reconnect the same two bindings to the new TableTestTableViewController we created.
Save changes, Build and Go, and if you're getting the results I'm getting, note the UITableView no longer functions properly
Solution:
With some more troubleshooting and some assistance from the iPhone Developer Forums, I've documented a solution! The main UIViewController subclass of the project needs an outlet pointing to the UITableViewController instance. To accomplish this, simply add the following to the primary view's header (TableTestViewController.h):
#import "TableTestTableViewController.h"
and
IBOutlet TableTestTableViewController *myTableViewController;
Then, in Interface Builder, connect the new outlet from File's Owner to TableTestTableViewController in the main IB window. No changes are necessary in the UI part of the XIB. Simply having this outlet in place, even though no user code directly uses it, resolves the problem completely. Thanks to those who've helped and credit goes to BaldEagle on the iPhone Developer Forums for finding the solution.
I followed your steps, recreated the project and ran into the same problem. Basically you are almost there. There are 2 things missing (once fixed it works):
You need to connect the tableView of the TableTestTableViewController to the UITableView you have on the screen. As I said before because it is not IBOutlet you can override the tableView property and make it and IBOutlet:
#interface TableTestTableViewController : UITableViewController {
UITableView *tableView;
}
#property (nonatomic, retain) IBOutlet UITableView *tableView;
Next thing is to add a reference to the TableTestTableViewController and retain it in the TableTestViewController. Otherwise your TableTestTableViewController may be released (after loading the nib with nothing hanging on to it.) and that is why you are seeing the erratic results, crashes or nothing showing. To do that add:
#interface TableTestViewController : UIViewController {
TableTestTableViewController *tableViewController;
}
#property (nonatomic, retain) IBOutlet TableTestTableViewController *tableViewController;
and connect that in the Interface Builder to the TableTestTableViewController instance.
With the above this worked fine on my machine.
Also I think it would be good to state the motivation behind all this (instead of just using the UITableViewController with its own UITableView). In my case it was to use other views that just the UITableView on the same screenful of content. So I can add other UILabels or UIImages under UIView and show the UITableView under them or above them.
I just spent many hours pulling my hair out trying to figure out why a UITableView wouldn't show up when when I had it embedded in a separate nib instead of in the main nib. I finally found your discussion above and realized that it was because my UITableViewController wasn't being retained! Apparently the delegate and datasource properties of UITableView are not marked "retain" and so my nib was loading but the controller was getting tossed... And due to the wonders of objective-c I got no error messages at all from this... I still don't understand why it didn't crash. I know that I've seen "message sent to released xxx" before... why wasn't it giving me one of those?!?
I think most developers would assume that structure that they build in an interface builder would be held in some larger context (the Nib) and not subject to release. I guess I know why they do this.. so that the iPhone can drop and reload parts of the nib on low memory. But man, that was hard to figure out.
Can someone tell me where I should have read about that behavior in the docs?
Also - about hooking up the view. First, if you drag one in from the UI builder you'll see that they hook up the view property (which is an IBOutlet) to the table view. It's not necessary to expose the tableView, that seems to get set internally. In fact it doesn't even seem to be necessary to set the view unless you want viewDidLoad notification. I've just broken the view connection between my uitableview and uitableviewcontroller (only delegate and datasource set) and it's apparently working fine.
Yes for some reason (please chime in if anybody knows why...) tableView property of the UITableViewController is not exposed as an IBOutlet even though it is a public property. So when you use Interface Builder, you can't see that property to connect to your other UITableView. So in your subclass, you can create a tableView property marked as an IBOutlet and connect that.
This all seems hacky and a workaround to me, but it seems to be the only way to separate a UITableViewController's UITableView and put it somewhere else in UI hierarchy. I ran into the same issue when I tried to design view where there are things other than the UITableView and that was the way I solved it... Is this the right approach???
I was able to make this work. I built a really nice dashboard with 4 TableViews and a webview with video. The key is having the separate tableView controllers and the IBOutlets to the other tableview controllers defined in the view controller. In UIB you just need to connect the other tableview controllers to the file owner of the view controller. Then connect the tables to the corresponding view controllers for the datasource and delegate.