I have an app with a UIWebView in a UIView.
URL to image
At this picture I see all my websites I visited. If I open Safari -> Developer -> Name of testing iPhone -> listed content of the picture. Are these visited sites different UIWebView instances?
Is my suspicious correct or what is there shown?
-(void)createWebView {
//[[self webView] removeFromSuperview];
//[[self view] willRemoveSubview:[self webView]];
[self setWebView:[[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]];
dispatch_async(dispatch_get_main_queue(), ^{
[[self view] addSubview:[self webView]];
});
[[self webView] setScalesPageToFit:YES];
[[self webView] setDelegate:self];
}
webView is a variable in my header file of type UIWebView and at every new entered URL the webview should be overwritten every time.
Every Instance of UIWebView holds its own history.
General Safari history is restricted to be accessed. And even if you managed to get them, i doubt your app will be accepted by Apple review team.
So the solution i think is to create NSMutableArray and loop on your UIWebViews and add their history into a single place -your created array-.
By so you will have all your local history in that array and do whatever you want with it.
Related
I have an app where I have slider where I have used icarousel. Below slider I have list of events. When I click on event, it go to event details.
What I noticed is that my iPhone is restarting if I go to event details from list and click back button from the details screen.
This is happening with iPhone 6 & above devices only.
Click to see the stacktrace
As its big, I provide link.
Just to add, I have also used UIRefreshControl on UITableView. Below is the code I have used.
refreshControl = [[UIRefreshControl alloc]init];
[mainTableView addSubview:refreshControl];
[refreshControl addTarget:self action:#selector(refreshTable) forControlEvents:UIControlEventValueChanged];
-(void) refreshTable {
[indicator startAnimating];
indexCounter.text = #"0";
indexCounter.hidden = YES;
occasionsArray = [[NSMutableArray alloc] init];
actualOccasionsArray = [[NSMutableArray alloc] init];
mainOccasionsArray = [[NSMutableArray alloc] init];
[refreshControl endRefreshing];
[mainTableView reloadData];
[self fetchHomeScreenOccassions]; // this is where I call webservice
}
Congratulations. You have:
Found a crasher bug in the NSURLSession helper daemon
Managed to create an animation on a view or other item that is so huge that you crashed the window server.
I can't tell you exactly how your code managed to do either of those things, but... one thing I notice is that you're nuking the entire table view and then reloading it. That's not necessarily the best way to approach this problem. Instead, you should load the data, and (assuming it comes in a consistent order) iterate through the items in your existing array as you receive items, deleting anything that should have been received already and adding any new items that aren't in the array yet.
I have tried all these (one, two, three, four) solutions, but after I come back from web view screen to previous viewController, it freezes for around 2 seconds(sometimes more). There is nothing in viewWillAppear which will cause the freezing.
Here is viewWillDisappear of web view controller :
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[detailWebView stopLoading];
detailWebView.delegate = nil;
NSLog(#"viewWillDisappear called !!!");
}
First viewController :
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController.navigationBar setBarTintColor:[UIColor colorWithRed:41.0/255.0 green:151.0/255.0 blue:132.0/255.0 alpha:1.0]];
UIImage *imagePlus = [[UIImage imageNamed:#"create.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
buttonCreate = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonCreate setImage:imagePlus forState:UIControlStateNormal];
[buttonCreate addTarget:self action:#selector(createActivity:) forControlEvents:UIControlEventTouchUpInside];
buttonCreate.frame = CGRectMake(self.view.frame.size.width - 40, 10, 16, 16);
[self.navigationController.navigationBar addSubview:buttonCreate];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"back", nil) style:UIBarButtonItemStylePlain target:nil action:nil];
[backButton setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
self.navigationItem.backBarButtonItem = backButton;
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
}
Update : I just confirmed that if I let the webView load completely and then go to previous viewController, there is no freeze observed.
I do the following, which is similar to what #Mrunal suggests but loads a valid page. I originally added this to deal with a situation where a loaded page had timers which continued to run forever after popping back from a UIWebView. For me this works well.
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Load a blank page as found things hang around.
[self.theWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
}
NB I do not call stopLoading as that stops the load request. This could be what is wrong with Mrunal's solution?
Try this in viewWillDisappear:
-(void)viewWillDisappear:(BOOL)animated {
[detailWebView setDelegate:nil];
[detailWebView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:#""]]];
[detailWebView stopLoading];
[super viewWillDisappear:animated];
}
Are you using NSURLProtocol to intercept the web requests from your UIWebView? The below answer is written on that assumption.
Loading of the web page involves sending out requests for multiple resources ( images, videos, html, javascript). Each of those resources have an URL that will be intercepted by the NSURLProtocol
Now if you close the webView before all the resources are loaded, NSURLProtocol takes sometimes to cancel all the open requests for resources it is intercepting and in this process freezing your app.
You will unregister from NSURLProtocol before you exit out of webView. So
override func viewWillDisappear{
NSURLProtocol.unregisterClass(/*your custom url protocol class name here*/)
}
should fix the freezing issue
PS: Sometimes you might have NSURLProtocol defined for the entire app, in which case I think it is better to separate out the NSURLProtocol for UIwebView from the rest of app. I don't know much about your project for me to comment if this is a feasible option for you
I think the webview might still process in the background. And I made the experience that it is quite annoying to release a UIWebView completely. You might want to have a look in the Profiler: up and close the webview's ViewController several times, the buffer should steadily increase.
This is why I came up to merge several solution approaches from stack overflow to finally and completely remove all storage from a webview and also stop it from running.
It is crucial, that the webview is set to be nil, to really deallocate it's memory, in former days we had the release method, which is now "obsolete" if you make use of the ARC properly.
- (void)releaseWebView:(UIWebView *)webView
{
/*
There are several theories and rumors about UIWebView memory leaks, and how
to properly handle cleaning a UIWebView instance up before deallocation. This
method implements several of those recommendations.
#1: Various developers believe UIWebView may not properly throw away child
objects & views without forcing the UIWebView to load empty content before
dealloc.
Source: http://stackoverflow.com/questions/648396/does-uiwebview-leak-memory
*/
[webView loadHTMLString:#"" baseURL:nil];
/*
#2: Others claim that UIWebView's will leak if they are loading content
during dealloc.
Source: http://stackoverflow.com/questions/6124020/uiwebview-leaking
*/
[webView stopLoading];
/*
#3: Apple recommends setting the delegate to nil before deallocation:
"Important: Before releasing an instance of UIWebView for which you have set
a delegate, you must first set the UIWebView delegate property to nil before
disposing of the UIWebView instance. This can be done, for example, in the
dealloc method where you dispose of the UIWebView."
Source: UIWebViewDelegate class reference
*/
[webView setDelegate:nil];
/*
#4: If you're creating multiple child views for any given view, and you're
trying to deallocate an old child, that child is pointed to by the parent
view, and won't actually deallocate until that parent view dissapears. This
call below ensures that you are not creating many child views that will hang
around until the parent view is deallocated.
*/
[webView removeFromSuperview];
webView = nil;
}
Please give it a try and call this method in viewWillDisappear:
If I have a UIWebView with mediaPlaybackRequiresUserAction = YES, then later in my app create a new UIWebView and set mediaPlaybackRequiresUserAction = NO on it, it also changes the value of that property on the first instance.
e.g. I have a UIWebView and then present a second UIWebView modally (for an ad), changing mediaPlaybackRequiresUserAction on the modal webView affects the presenting UIWebView.
Any ideas why this is? Are UIWebViews all backed by a single instance?
Link to sample project here.
not sure your app purpose, just try this way:
- (IBAction)unwind:(UIStoryboardSegue *)unwindSegue
{
[self TS_updateLabel];
[[self webView] setMediaPlaybackRequiresUserAction:YES];
[self TS_reloadWebView];
}
....
in method TS_reloadWebView
if (self.webView.isLoading) {
[self.webView stopLoading];
}
[self.webView loadHTMLString:htmlString baseURL:baseURL];
I guess it also is UIWebView bug .... but now this way maybe can solve your problem.
I'm developing a PhoneGap Build application, but needed a way to prompt my user to open local files in Adobe Reader (inAppBrowser will not work for my situation). I found a 3rd party plugin for PhoneGap that does what I need. However it only does it for remote .pdf files. I have figured out how to alter the plugin code to work with local files on the iPad/iPhone but it seems to close my application when the user opens the pdf in Adobe Reader.
I know almost nothing about objective C, Xcode, etc.
Desired functionality is:
User navigates my app searching or browsing for files
Finds desired file
Selects file
User is presented with "open with" options of which one is Adobe reader
User selects Adobe, PDF opens
User returns to my app in location they left it
I have it all working except on step #6 above my app seems to be closed. If I press the home button twice app show up at the bottom of iPad but when selected app starts from closed state showing splash screen. I'd like it to be where the user left it.
I believe the relevant code is
NSURL *fileURL = [NSURL fileURLWithPath:localFile];
UIDocumentInteractionController *controller = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
[controller retain];
controller.delegate = self;
controller.UTI = uti;
CDVViewController* cont = (CDVViewController*)[ super viewController ];
//CGRect rect = CGRectMake(0, 0, cont.view.bounds.size.width, cont.view.bounds.size.height);
CGRect rect = CGRectMake(0, 0, 1024, 768);
[controller presentOpenInMenuFromRect:rect inView:cont.view animated:YES];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: #""];
[self writeJavascript: [pluginResult toSuccessCallbackString:callbackID]];
[callbackID release];
[path release];
[uti release];
Where this line
[controller presentOpenInMenuFromRect:rect inView:cont.view animated:YES];
prompts the user to select Adobe. Is there a parameter I can pass here to not have my application shut down once the user selects to open the pdf in Adobe?
Thanks!
The plugin I have altered in its original state can be found and discussed here:
http://www.tricedesigns.com/2012/08/15/open-with-in-ios-phonegap-apps/
I am trying to use a singleton class to choose custom content to display based on the selection made by the user. It goes like this: a list is displayed, users select one of the rows in the list, and the app goes into another ViewController view. The ViewController used is the same for all the list options, however the content is different. Currently I managed to do this for only 1 option, and am trying to use a singleton class to tell the app which content to choose from.
This is what happens when the option "Raffles Landing Site" is chosen:
if(landmarkSelected== #"Raffles Landing Site") {
RafflesLandmarkInfo *rafflesLandmarkInfo = [[RafflesLandmarkInfo alloc] initWithNibName:#"RafflesLandmarkInfo" bundle:nil];
[self.navigationController pushViewController:rafflesLandmarkInfo animated:YES];
[rafflesLandmarkInfo release];
This opens a UIWebView implemented as follows:
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"raffles" ofType:#"html"]isDirectory:NO]]];
I created a singleton class as described here: http://www.galloway.me.uk/tutorials/singleton-classes/
I added an NSMutableString property to it and changed the previous codes to the following:
if(landmarkSelected== #"Raffles Landing Site") {
LandmarkController* instance = [LandmarkController sharedInstance];
[instance.activeLandmark setString:#"raffles"];
RafflesLandmarkInfo *rafflesLandmarkInfo = [[RafflesLandmarkInfo alloc] initWithNibName:#"RafflesLandmarkInfo" bundle:nil];
[self.navigationController pushViewController:rafflesLandmarkInfo animated:YES];
[rafflesLandmarkInfo release];
and
if (instance.activeLandmark ==#"raffles"){
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:instance.activeLandmark ofType:#"html"]isDirectory:NO]]];
}
but the app crashes when I select Raffles Landing Site from the list of options. The culprit seems to be
[instance.activeLandmark setString:#"raffles"];
How do I set the activeLandmark string in the first ViewController so when it loads the second ViewController it displays content based on the value set in the first ViewController?
In your singleton, is the activeLandmark string being alloced/initialized before you try and assign to it?