I am new to Objective-C.
I have a table view populated with links that the user has added. When the user clicks on one of the cells in the table view, they are guided to a second view controller with a web view that displays the website of the link. However, when I run the app the web view appears blank. How do I fix this problem? There are no errors noted in the console either.
Table View .m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showWebsite"]) {
UITableViewCell *cell = (UITableViewCell*)sender;
NSURL *url = [NSURL URLWithString:cell.textLabel.text];
NSString *string = url.absoluteString;
SecondViewController *vc = [segue destinationViewController];
vc.url = string;
}
}
Second View Controller .m
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *URL = [NSURL URLWithString:[self.url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[self.webView loadRequest:request];
}
Can you try placing the 3 lines from the
- (void)viewDidLoad
to the
-(void)viewDidAppear:(BOOL)animated
instead?
Related
I really need help please. Initially, by tapping on a tab bar item, I will load a webview on Gym VC user will then scroll down the web view
What I am trying to accomplish is when user tap on the same tab bar item again, the webView will reload again. I managed to call the method handleRefresh from MyTabBarController But the method doesn't do anything at all. Any guidance is much appreciated.
Currently I have the following code
MyTabBarController.m
#import "GymNavigationController.h"
#import "Gym.h"
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if([viewController isKindOfClass:[GymNavigationController class]]){
Gym *myGym = [[Gym alloc] init];
[myGym handleRefresh:nil];
}
}
Gym.m
#import "Gym.h"
#import "AppDelegate.h"
#import "GymDet.h"
#import <QuartzCore/QuartzCore.h>
#interface Gym () {
AppDelegate *appDelegate;
NSString *sURL, *sRefresh;
}
#end
#implementation Gym
#synthesize webView;
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sURL = appDelegate.gURL;
sURL = [sURL stringByAppendingString:#"/apps/gym.asp?"];
NSLog(#" The sURL to be load for the current page : %# ", sURL);
sRefresh = sURL;
[defaults setObject:sRefresh forKey:#"txtRefresh"];
[defaults synchronize];
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView setDelegate:(id<UIWebViewDelegate>)self];
[webView loadRequest:urlRequest];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[webView.scrollView addSubview:refreshControl];
}
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//[self handleRefresh:nil];
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
-(void)viewDidDisappear:(BOOL)animated{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
- (void)handleRefresh:(UIRefreshControl *)refresh {
//--- Call the stored txtMemCode, something like session ---
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
sRefresh = [defaults objectForKey:#"txtRefresh"];
NSURL *url = [NSURL URLWithString:sRefresh];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
[refresh endRefreshing];
}
First i would like to suggest why you're initiating a new Gym object every time tabbar is tapped you should take a reference of the Gym object and initialise it if its nil then process ahead with the reference, but it maybe your requirement and if it is i would like to suggest you to create a BOOL variable lets say isUpdateRequire and when you're instantiating your viewcontroller assign isUpdateRequire = true. Then in the end of view did load or view will appear (according to your need) check
if isUpdateRequire {
[self handleRefresh:nil]
}
Alternatively you can create protocols in your webviewcontroller and assign its delegate to your tabbarcontroller and fire the delegate method when ever required.
and if you don't want the method to call when you come back to vc simply put this condition in viewWillAppear
if self.isMovingToParentViewController {
[self handleRefresh:nil]
}
Edited
My initial webview is loaded when a tabbar is pressed, then when clicked on the webview, I called
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
to detect the URLString clicked
When the string matches my destination string, I will call the segue [self performSegueWithIdentifier:#"NewsDet" sender:self]; and also pass the URLString and load the detail page on another ViewController
Now, when I click the another tabbar and then click back to this tabbar. The detail page remains. I want to refresh back to initial page. How do I do so?
Is it the I need to create a new class with a subclass of tabviewcontroller? Please help.
Gym.m
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sURL = appDelegate.gURL;
sURL = [sURL stringByAppendingString:#"/apps/gym.asp"];
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView setDelegate:(id<UIWebViewDelegate>)self];
[webView loadRequest:urlRequest];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[webView.scrollView addSubview:refreshControl];
}
- (void)handleRefresh:(UIRefreshControl *)refresh {
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
[refresh endRefreshing];
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sURL = appDelegate.gURL;
sURL = [sURL stringByAppendingString:#"/apps/gym.asp"];
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView setDelegate:(id<UIWebViewDelegate>)self];
[webView loadRequest:urlRequest];
}
GymDet.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
sURL = self.urlString;
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView setDelegate:(id<UIWebViewDelegate>)self];
[webView loadRequest:urlRequest];
}
Basically I have 5 tab controllers. Each Tab has a Navigation Controller. When I click on say Tab-A it will load initial webview in VC1 then when I click on webview URL, it will navigate to a new VC say VC2 and load the detailed page.
Now, if I click on say Tab-B and back to Tab-A. I want it to load the initial webview or VC1. Now, my program always stay at VC2.
After clarification on what you're trying to do...
Your issue has nothing to do with webviews or loading URLs. The problem is that you are navigating to a new VC in your NavigationController, then switching tabs, then switching back and you are still at the "pushed" VC.
A comment not related to the problem:
I am on Tab-A, viewing VC-A1... Via "normal" Navigation Controller
action, VC-A2 slides-in from the right. Now I select Tab-B, and I see
VC-B1. Now, I want to switch back to Tab-A, and I expect to see what
was there: VC-A2... but instead, you want to send me back to VC-A1. That really doesn't follow Apple's interface guidelines, and can be very confusing to your users.
However, to accomplish that, you want to subclass UITabBarController and implement didSelectViewController:
#import "MyTabBarViewController.h"
#interface MyTabBarViewController () <UITabBarControllerDelegate>
#end
#implementation MyTabBarViewController
- (void) viewDidLoad {
[super viewDidLoad];
self.delegate = self;
}
-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[UINavigationController class]]) {
[(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
}
}
#end
That will work, but it will "reset" any Navigation Controller in every tab. You'd need to add some other logic to handle only the first tab.
(original answer)
viewDidLoad is only called once - when the view loads. Switching between tabs does not "re-load" the view.
You probably want to reload your original URL in viewWillAppear as that will be called each time you switch back to that tab.
Although, you probably also want to check if the original URL is the current one displayed - you likely only want to reload it if it's not.
And... you never want to call [self viewWillAppear:YES]; -- that is a notification provided by the system.
I'm creating an iphone application where 2 URLs are passed from an xml file and sent from a UITableView to a detail view through a segue to be loaded in a UIImageView.
This is my prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"detail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSMutableString *imgURL1 = [feeds[indexPath.row] objectForKey: #"imageURL1"];
[[segue destinationViewController] setImg1:imgURL1];
//img1 is declared in the detailviewcontroller class
}
}
And this is my viewDidLoad in the detailViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL * imageURL1 = [NSURL URLWithString:self.img1];
NSData * imageData1 = [NSData dataWithContentsOfURL:imageURL1];
UIImage * imag1e = [UIImage imageWithData:imageData1];
appImage1.image = imag1e;
//appImage1 is also declared in the detailViewController class
}
Now the problem is that when i run the app nothing is displayed in the appImage1 and no error or bug is reported.
Thanks for your help
Several problems here:
1) Why mutable string? NSString is enough.
2) It is not really safe to rely on the "selected row". That is just a side effect of picking a row. Ideally, you should use the sender.
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell*)sender];
3) Don't call the URL load on the main thread. Rather, use an asynchronous loading with NSURLRequest and NSURLConnection. Set the image in the didFinishLoading callback.
4) Check what else could have gone wrong:
the image view is nil.
the string is nil.
The URL is nil or invalid.
the server is not responding or not sending data or taking too long.
I fixed the problem.
Apparently, the problem was with the URL. The xml parser was storing the url in the url variable with a space in the beginning so all I had to do is to use stringByTrimmingCharactersInSet so the segue method looks like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//sends the image link
NSString *imageURLS = [feeds[indexPath.row] objectForKey: #"appImageURL"];
imageURLS = [imageURLS stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *img = [NSURL URLWithString: imageURLS];
[[segue destinationViewController] setAppImageURL:img];
}
I am passing a NSURL from my pickerviewcontroller to my mainviewcontroller. The url is dependent on the user choice in pickerviewcontroller. It works fine, but the user has to repetedly go to the pickerviewcontroller every time the app is restarted to make the choice.
Maybe the code will explain the problem better: This is the pickerviewcontrollers relevant parts...
//The save button on the pickerviewcontroller
- (IBAction)selectedRow:(id)sender {
MainViewController *vc1 = [self.storyboard
instantiateViewControllerWithIdentifier:#"webview"];
vc1.destinationweb = selectedRow;
[self presentViewController:vc1 animated:YES completion:nil];
Once in MainViewController the destinationweb log shows the address of the user choice in pickerview. But If I turn off the app or go forwards in the app (I have another view controller) and then back to MainViewController - it shows destinationweb = null
This is the MainViewController relevant parts:
- (void)viewDidLoad {
{
//webView.hidden = YES;
self.webView.delegate = self;
NSURL *url = destinationweb;
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
NSLog(#"destinationweb shows= %#", destinationweb);
}
[super viewDidLoad];
}
I have no idea what I am supposed to do to make the MainViewController remember the url until another row in picker view is selected??
Just save the url string in user defaults and retrieve the url string in view controller
- (IBAction)selectedRow:(id)sender
{
MainViewController *vc1 = [self.storyboard
instantiateViewControllerWithIdentifier:#"webview"];
//Instead of passing it just save the url string in user defaults
NSString *urlString = [selectedRow absoluteString];
[[NSUserDefaults standardUserDefaults] setObject:urlString forKey:#"UserURL"];
//vc1.destinationweb = selectedRow;
[self presentViewController:vc1 animated:YES completion:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//webView.hidden = YES;
self.webView.delegate = self;
NSString *urlString = [[NSUserDefaults standardUserDefaults] stringForKey:#"UserURL"];
NSURL *url = [NSURL URLWithString:urlString ];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
NSLog(#"destinationweb shows= %#", destinationweb);
}
if you want to keep the value once the app is restarded, you should storage the value (url) in a file, so when you restart it you can read it from there.
I have a UIWebView class that is added to each storyboard on load, but when passing into this class the page I require form the parent ViewController it only show the file from the first ever page and on each different page/viewController its the same even though I set it different on each.
Is it somehow caching this page and if so, how can I have a clean UIWebview everytime?
my UIwebview class m file (ContentView.m):
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
NSString *urlpath = [[NSBundle mainBundle] pathForResource:pageToDisplay ofType:#"html" inDirectory:#"pageContent"];
NSURL *url=[[NSURL alloc] initFileURLWithPath:urlpath];
NSURLRequest *request=[NSURLRequest requestWithURL:url];
[self loadRequest:request];
}
return self;
}
My Parent view passes the requested page using the following variable pageToDisplay:
Parent View m file:
#import "ContentView.h"
- (void)viewDidLoad {
ContentView *dispalyPageContent = [[ContentView alloc] init];
[dispalyPageContent setPageToDisplay:#"THEpg1"];
[self.view addSubview:dispalyPageContent];
//--
[super viewDidLoad];
}
For each other parent view the code is the same but the [displayPageContent setPageToDisplay:#"THEpg1"]; which should change the page I want, e.g. next view would be [displayPageContent setPageToDisplay:#"THEpg2"];
Is it possible to clear this and load a fresh request each time?
It's because when you call ContentView *dispalyPageContent = [[ContentView alloc] init]; in your viewDidLoad , you init it with:
NSString *urlpath = [[NSBundle mainBundle] pathForResource:pageToDisplay ofType:#"html" inDirectory:#"pageContent"];
And in pathForResource:pageToDisplay at the moment of initializing is some trash.
And then, when you call [dispalyPageContent setPageToDisplay:#"smth"] , it changes nothing, because your class ContentView has been already inited with some trash in PageToDisplay
(Also, you call [[ContentView alloc] init]; and in your code there is only initWithFrame:... for objects of ContentView class)
You can solve this in this way:
1) in your ContentView.m
- (id)initWithFrame:(CGRect)frame pageToDisp:(NSString *)pageToDisp {
self = [super initWithFrame:frame];
if (self) {
NSString *urlpath = [[NSBundle mainBundle] pathForResource:pageToDisp ofType:#"html" inDirectory:#"pageContent"];
NSURL *url=[[NSURL alloc] initFileURLWithPath:urlpath];
NSURLRequest *request=[NSURLRequest requestWithURL:url];
[self loadRequest:request];
}
return self;
}
2) In your ContentView.h:
- (id)initWithFrame:(CGRect)frame pageToDisp:(NSString *)pageToDisp
3) And then, in viewDidLoad:
- (void)viewDidLoad {
ContentView *dispalyPageContent = [[ContentView alloc] initWithFrame:someFrame pageToDisp:#"THEpg1"];
[self.view addSubview:dispalyPageContent];
//--
[super viewDidLoad];
}