I'm sure this is a very dumb question (or one that reveals terrifying levels of ignorance), but as an iOS newbie I'm trying to lash an app together as a favour to a friend - and any help would be greatly appreciated.
I have a multi-tab app, which is running fine. On the last tab, I'd like have a table view giving access to a variety of pdf or html files, to be stored in the bundle (and added to in future updates). Basically I want it so that if the user selects "Story pdf" in the table view, it loads up NextView with a UIWebView showing said pdf. If they select "Info table" then that UIWebView loads up info.html instead. It'll only ever be those two file types.
I've got the table view running and a new view ready and waiting, I just can't work out the next bit. Should I store names/file types in a plist? Is NSFileManager my friend here? If anyone has any pointers or knows of a sample project or chunk of code that does something similar, it would be fantastic.
Thanks for listening :-)
Your UITableView will have a delegate (possibly your view controller) and you need to implement this method from the UITableViewDelegate protocol:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
you get the indexPath of the selected cell and then you work out what to do next.
Related
My original plan was to use a split view controller to have a table view and a generic view beside it for an iPad app. Then I realized I could not use a split view controller as a child controller. So, I've been experimenting with using a table view controller instead, and I've got pretty good results so far. Essentially, I'm using the tableview's header view as a container for the various views I'll be using depending on which row is selected. The only unresolved issue is that images for a website are not displayed in the UIWebView the first time it is presented. If I tap another table row that displays a web view, it displays fine. And if I tap the original one again, it displays fine, too.
It doesn't matter which one I tap first. It's always the first one that doesn't display images. Instead of displaying the images, it displays the names of the image files.
When I tried the analogous thing with a split view controller, I didn't have this problem.
Any ideas what I should be looking for? Or is there something I need to be doing that I must not be doing?
If it matters, the page being loaded is just a thumbnail page on a remote server, created with Irfanview's HTML thumbnail page generator.
P.S. After further testing, it is really the very first presentation only that doesn't work as expected. By very first, I mean the first per app session. The UIWebview is presented as a subview of the table header. The tableview controller is presented as a popover from a button of another controller that is presented when a user taps an image. Even if I dismiss all these layers of controllers, etc., if I instantiate them again, the UIWebView displays properly.
This suggests possibly loading a dummy UIWebView before starting, but that seems kludgy.
I'm getting exactly one call to webViewDidStartLoad: and exactly one call to webViewDidFinishLoad: and no calls to webView:didFailLoadWithError:.
KLUDGE:
The kludge works. Here it is:
In my table view controller, I create a boolean property URLHasBeenRequested and set it to NO in viewDidLoad. Then I ask for a reload thus:
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
if (!self.URLHasBeenRequested) {
//On first pass, try a second request.
[webView loadRequest:webView.request];
self.URLHasBeenRequested = YES;//Set this flag so a duplicate request happens only the first time.
}
}
I suspect this has more to do with the way the UITableView is loading the header and trying to allocate memory during that process, than with the UIWebView itself. For whatever reason, the UIWebView's loading seems to be getting interrupted while the rendering of the UITableView is still finishing ( just a guess ).
One thing you might try would be to go ahead and setup your table header by adding the UIWebView subview, but not calling "loadRequest" right away. You could, for example, wait until the rest of the visible cells of the table have been loaded, and then load the header view last. You can detect when that occurs like this:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([indexPath row] == ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row){
[webView loadRequest:webView.request];
}
}
This is, admittedly, also a somewhat kludgy workaround, but at least you're not having the UIWebView load the content twice. I also haven't tested this myself, and without seeing your actual table loading code, it's hard to say if the root of the problem lies somewhere else, but let me know if this works!
I am trying to set up a UITableView inside of a UIViewController. I'm doing this because it allows me to add a top bar with save and cancel buttons. I'm using storyboard and static cells to model the tableview to get input from the user (think of the create new event in Apple's calendar app). I have the view in Xcode, but when running it on my phone or the simulator, the tableview does not display. Here is the simple view in Xcode:
And this is how it displays when running it:
I've read about adding delegates and setting the datasource and such, but really this is all just going to be static cells with text fields, no data being loaded. Why is this happening and what can be done to fix it? Thanks!
#Made2k It looks like you found a solution, but for others who come across this with the same issue, note that you can only use a UITableView with static cells inside of a UITableViewController. This is not a well-documented fact, but apparently only UITableViewController knows how to handle the layout of static cells, whereas a regular UIViewController just needs to implement the UITableViewDelegate and UITableViewDataSource protocols in order to handle display of content in a UITableView added either programmatically or via Storyboard/Nib.
Hopefully this will save someone some time. #Made2k's solution is fine, but does make your storyboard unnecessarily busy. If you don't need to use a UIViewController, then just do your work inside a regular UITableViewController and save yourself a headache.
If you want to use a UITableView in a UIViewController you have to make the ViewController a data source and a delegate of the TableView and then implement methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In case of a static table, in the cellForRowAtIndexPath you'd return outlets of the static cells. For a detailed description check out this answer:
https://stackoverflow.com/a/19110821/3110536
I ended up thinking about this in a different kind of way. The problem I thought I was having was I wanted all the features that a navigation controller provides, but I needed this to be the base of the controller, i.e. nothing to go back to. I was thinking that the only way to do this was to create a UIViewController and add the table view and such in there, but what I came up with is to simply just create a new navigation controller and now this view shows up as the root view like so:
I don't know if this is the best practice, but hopefully it can help somebody else if they are having this problem.
Man, following Hack really works!
You should give it a try!
In my requirement I wanted to add buttons in my Static cells too!and Toggle the visibility of the TableView
[self.tableView setHidden:YES/NO];
and Reload it with new data
[self.tableView reloadData];
and so many things is possible with that way of doing it!
https://stackoverflow.com/a/19110821/1752988
Hope the above link would help you! (Y)
I have been following many examples to add addressbook functionality to one of my views.
I am getting stumbled between Addressbook API, ABPeoplePickerNavigationController and how to fit them into UITableView. I am highly confused as to what all controls I need to put over my storyboard to get the whole thing working.
What I need is:
Last Name First Name (in table view display) along with an image icon (same for all contacts)
Phone Number (needed but not necessarily to be displayed)
When single cell is clicked, it should present a popover that offers certain number of options in a popup menu (but contacts table view should not disappear with the popover)
Can anyone point me exact example that achieves this?
XCode steps that can optionally achieve would also be highly appreciated.
I believe you are a little confused with how the AddressBook API works.
There's an apple developer reference that have a good example of how you can use the API.
I have linked it here Apple QuickContact Reference
In summary, you can preload certain data that you are keen to display on your tableview into NSArray. Then upon UITableView's didSelectRowAtIndexPath call the respective method to push the another viewcontroller to display.
Hope that clears up your doubt.
I'm searching any tutorial or explication how to add a "level" in a table-view.
I'm using XCode 4.3.2. I've created a Master-Detail App, and I did all what I should for a working application. But I have only one Level in my table view, and have absolutely no idea how to get a second level.
I searched a lot in Google and in the Apple documentation, but I haven't found anything..
My wish is to have the list, when you click on an object of the list, you go to the second level with a new list, and when you click on an object of the second list, it changes the Detail View.
I think what you mean is going to the next view controller.
What you should do is use the delegate method - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
(Link to doc)
Here you can create a new tableViewController, e.g.
UITableViewController *newTable = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
[self.navigationController pushViewController:newTable animated:YES];
However, what you want to do (I guess) is send data to it which is should show. So, in your newTable tableviewcontroller you should create a new init method which allows you to send in the data you need. For instance an array. The class can then handle that data and show it as you please.
I hope that answered your question.
I'm working on an iPhone app that will have involve a lot of forms. Currently I have a ViewController class for each settings page which has an UITableView loaded with possible settings. When someone clicks on a setting they are taken taken to a new view to enter the form value, or allowed to enter things in place.
What's the best way to keep things DRY? What pieces of this implementation could be implemented once and re-used?
When someone clicks on a settings option which goes to a new view how can I create this view and add a text field according to the data type (uitextfield or picker or something else) in code?
You can programmatically:
create view hierarchy
UIButton
UILabel
You get the idea.
However, I would recommend getting your logic working for a few of the cases, and then it should become obvious what parts are redundant as you find yourself typing in the same thing over and over. At that point, refactor to get the redundant code into a re-usable form.
HTH.
If you have a tableView, the flow is to create the viewController of the selected settings in the didSelectCell method of your tableView delegate and to push it through the current viewController's navigation controller.
here's a sample:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.navigationController pushViewController:[self settingsViewControllerAtIndexPath:indexPath] animated:YES];
}
so you'll have to implement the method:
- (UIViewController*)settingsViewControllerAtIndexPath:(NSIndexPath *)indexPath;
wich will return the viewController managing the settings associated with the selected row of your root tableView.
If your forms are pretty statics, you should consider using a xib in order to minimize the amount of code needed. it isn't a perfect answer to your "how to keep DRY" but it's neat enough ;)
Good luck.