How to swap two UIWebViews in iOS - ios

In my app I have a sliding view that holds UIWebView, that I want to substitute with another UIWebView that has already loaded content on user tap instead of loading the current view.
I tried just simply assign one view to another:
UIWebView* webView1 = [[UIWebView alloc] initWithFrame:frame];
UIWebView* webView2 = [[UIWebView alloc] initWithFrame:frame];
webView1 = webView2; // didn't work
Any help is highly appreciated!

If you need to keep them both around, you could just hide the one that should go away:
[webView1.superview addSubview: webView2];
[webView1 setHidden: YES];

Try this:
[webView1.superview addSubview: webView2];
[webView1 removeFromSuperview];

My solution:
Get the whole HTML string of the webView2:
NSString *htmlString = [webView2 stringByEvaluatingJavaScriptFromString: #"document.body.innerHTML"];
Load this HTML string to webView1.

Related

IOS/Objective-C: Deallocate web view in Detail View Controller

I have a master table and detail view controller. The detail VC shows URLs through a web view.
If using the built in navigation of the master/detail setup, if I go back and then press a different table cell, the detail view will update the web view. This is true whether I use a UIWebView or a WKWebView.
However, within the detail view, without having to go back to the table, I want to give the user the option to view more than one url through the same web view. I am trying to do this in viewwillappear by changing the url for the request. However, the UIWebView (or alternatively WKWebView) continue to show the same url. I can't seem to get rid of the first url.
I've tried all kinds of ways to close or stop the existing web view, clear the cache, delete cookies etc. before reloading the new one but still see the same url. Would appreciate any suggestions. Here is my code and some of the things I've tried that don't work:
-(void) changeURL: (NSNumber*)param {
NSURL *testurl1=[NSURL URLWithString:#"http://www.apple.com"];
NSURL *testurl2 =[NSURL URLWithString:#"http://www.google.com"];
//if param is 1 {
_urlToLoad = testurl1;}
else {
_urlToLoad = testurl2;}
}
Edit: Method below is updateInterface, not viewWillAppear
-(void) updateInterface {
UIWebView *webView;
NSURLRequest *request=[NSURLRequest requestWithURL:_urlToLoad];
webView = nil;//This blocks the web view from loading at all for some reason I can't understand. Setting wkWebView to nil does not block loading.
[webView stopLoading];//no effect
[webView loadRequest:request];
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSString *myDomain = #"www.google.com";
for(NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
if([[cookie domain] isEqualToString:myDomain]) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
}
//wkwebview version
WKWebView *wkwebView;
WKWebViewConfiguration *wkConfig = [[WKWebViewConfiguration alloc] init];
wkwebView = nil;
wkwebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:wkConfig];
wkwebView.navigationDelegate = self;
[wkwebView loadRequest:request];
[webView addSubview:wkwebView];
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
webFrame.origin.y = 100.0; // statusbar
webFrame.origin.y -= 100.0; // statusbar 20 px cut from y of frame
webView = [[UIWebView alloc] initWithFrame:webFrame];
}
The UIViewController method "viewWillAppear" has the following signature in Objective-C:
- (void)viewWillAppear:(BOOL)animated
, you implemented it without any arguments.
The result is that, instead of being taken as an override of the original method defined in the superclass UIViewController, it is treated as a brand new, custom method introduced by your subclass; and unless you call it explicitly somewhere, it will never execute.
Source: SDK Reference

IOS/Objective-C: Force UIWebView to reload

I have a screen that shows a web view. However, I allow people to cycle through different web views by updating an object. When I load the first page, the web view loads fine. However, when I try to update the page from the new object in viewwillappear, while other elements such as a title that goes above the webview load fine, the web view does not refresh.
//in viewWillAppear
self.title = self.file.imageDescript;//The title loads fine
NSString *urlBase = #"https://www.~com/images/";
NSString * imagename = self.file.imagename;
NSString *url = [NSString stringWithFormat:#"%#%#",urlBase,imagename];
NSURL *realUrl = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:realUrl];
[webView loadRequest:request];
I have tried various versions of setNeedsDisplay and also applied these to subviews of the web view without success as in this method:
- (void) forceRedrawInWebView:(UIWebView*)webView {
NSArray *views = webView.scrollView.subviews;
for(int i = 0; i<views.count; i++){
UIView *view = views[i];
//if([NSStringFromClass([view class]) isEqualToString:#"UIWebBrowserView"]){
[view setNeedsDisplayInRect:webView.bounds]; // Webkit Repaint, usually fast
[view setNeedsLayout]; // Webkit Relayout (slower than repaint)
// Causes redraw & relayout of *entire* UIWebView, onscreen and off, usually intensive
[view setNeedsDisplay];
[view setNeedsLayout];
// break; // glass in case of if statement (thanks Jake)
//}
}
}
I have read in one SO answer that since IOS8.2, refresh of UIWebView no longer works (as WKWebView) has replaced it. I would switch to WKWebView except that it is not supported in storyboards, apparently, and I have a bunch of stuff going on in the storyboard.
Note: this has nothing to do with refreshing the same web url because content has changed on a server. It has to do with loading an entirely different web url in the UIWebView
Can anyone suggest way to fix this?

UIActivityIndicator does not show/hide based on the loading of the UIWebView

I want to load a URL on a UIViewController with an UIWebView and UIActivityIndicatorView, but UIActivityIndicator never appears and UIWebView never loads the URL.
This is my code:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.title = #"Web";
[self displayURL:[NSURL URLWithString:#"(Website)"]];
}
-(void) webViewDidFinishLoad:(UIWebView *)webView {
[self.loadView stopAnimating];
self.loadView.hidden = YES;
}
-(void) displayURL:(NSURL *) aURL {
self.web.delegate = self;
self.loadView.hidden = NO;
[self.loadView startAnimating];
[self.web loadRequest:[NSURLRequest requestWithURL:aURL]];
}
If you add your webView by code, you need add
[self.view addSubview: web];
after you created webView, and of course you need to add UIActivityIndicatorView as a subView of webView or superView, so you need to add [web addSubview: loadView] or [self.view insertSubview: loadView aboveSubview: web];.
And about the URL, if your website URL is like www.google.com, you need to change #"(Website)" to the real URL. If your website is a file copied in your project, you need to change [NSURL URLWithString: ]; to [NSURL fileURLWithPath:[NSBundle mainBundle][pathForResource: ofType:]];.
Really poorly formulated question.
UIWebViewController does not work
UIWebViewController does not exists, you are talking about a UIWebView in a UIViewController
Code is very incomplete

UIWebview tripadvisor redirection bug to their app?

Recently I just discovered a little issue.
I'm using UIWebview to load some url some times nothing really fancy, just basic init:
self.webview = [[UIWebView alloc] initWithFrame:CGRectMake(0, navBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height-navBar.frame.size.height)];
self.webview.opaque = NO;
self.webview.delegate = self;
self.webview.scalesPageToFit = YES;
[self.view addSubview:self.webview];
and i'm loading the url like this:
if(self.webview)
{
[self.webview loadRequest:[NSURLRequest requestWithURL:url]];
}
The problem that i got is when i try to redirect to tripadvisor mobile page I got a pop up saying that my version is not handled anymore and that i need to update it, the thing is that even with the last update it doesnt work...
And it's the same for ios6, 7 and 8 and only for IPHONE ...
Is there anybody who got the same problem ? and maybe fixed it ?
Thanks !
Here is the image of the popup:
I just solved by change UIWebView's user-agent
NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:#"Safari iOS 8.0 - iPhone", #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
put it before your webview initialize.
Hope this helps.

Memory hanging around after dismissModalViewControllerAnimated:YES

I am presenting a modal view controller which contains a UIScrollView with a bunch of images. When I dismiss my modal view controller I can see in my Allocations (instruments) that memory assigned to the images is hanging around but not causing leaks.
Causing me some confusion and any help would be great. Here is what I have...
UIViewController - DollViewController: This is my main view controller that I am presenting my modal over. Here is the code -
-(IBAction)openDollCloset {
NSLog(#"Open Closet");
[self playSound:#"soundMenuClick"];
ClosetViewController *closet = [[ClosetViewController alloc] initWithNibName:#"ClosetViewController" bundle:nil];
closet.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentModalViewController: closet animated: YES];
closet.delegate = self;
closet.addToCloset = NO;
[closet setCurrentDoll:myDoll];
[closet openCloset];
[closet release];
[self closeSubmenu];
}
I create my scrollview manually to hold the outfit images.
The object closetScroller is defined with #property (nonatomic, retain) UIScrollView *closetScroller; with a release in dealloc.
- (void)setScrollerValues {
if (closetScroller == nil)
{
self.closetScroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 400)];
[self.closetScroller setDecelerationRate:UIScrollViewDecelerationRateFast];
[self.closetScroller setDelegate:self];
[self.closetScroller setPagingEnabled:YES];
[self.closetScroller setShowsHorizontalScrollIndicator:NO];
[self.view addSubview:closetScroller];
}
[self.closetScroller setContentSize:CGSizeMake(outfitCount * 320, 400)];
}
After creating the scrollView I add the images to the scroller. I believe I am releasing everything right. I am creating the images with NSData objects and releasing them.
- (void)addOutfitsToScroller {
// Clear out any old images in case we just deleted an outfit
if ([[closetScroller subviews] count] > 0)
{
CATransition *fade = [CATransition animation];
[fade setDelegate:self];
[fade setType:kCATransitionReveal];
[fade setSubtype:kCATransitionFromRight];
[fade setDuration:0.40f];
[[self.closetScroller subviews] makeObjectsPerformSelector: #selector(removeFromSuperview)];
[[closetScroller layer] addAnimation:fade forKey:#"FadeButtons"];
}
// Set the pageControl to same number of buttons
[pageControl setNumberOfPages:outfitCount];
// Load the outfit image and add it to the scroller
for (int i = 0; i < outfitCount; i++)
{
NSArray *savedDataArray = [[NSArray alloc] initWithArray:[closetItemsArray objectAtIndex:i]];
UIImageView *v = [[UIImageView alloc] initWithFrame:CGRectMake(320*i, 0, 320, 400)];
[v setUserInteractionEnabled:NO];
[v setAlpha:0.40f];
NSData *imageData = [[NSData alloc] initWithContentsOfFile:[savedDataArray objectAtIndex:1]];
UIImage *outfitImage = [[UIImage alloc] initWithData:imageData];
UIImageView *closetImage = [[UIImageView alloc] initWithImage:outfitImage];
[imageData release];
[outfitImage release];
[savedDataArray release];
CGSize frameOffset;
#ifdef LITE_VERSION
frameOffset = CGSizeMake(40, 60);
#else
frameOffset = CGSizeMake(20, 10);
#endif
closetImage.frame = CGRectOffset(closetImage.frame, frameOffset.width , frameOffset.height);
[v addSubview:closetImage];
[closetImage release];
[self.closetScroller addSubview:v];
[v release];
}
}
This all works great. Then when the user selects the "Close" button or selects an outfit I call:
[self.delegate closeClosetWindow];
Which calls the delegate method in the parentViewController which simply makes this call:
[self dismissModalViewControllerAnimated:YES];
I have also tried calling dismissModalViewControllerAnimated:YES from the modal view controller itself. It simply forwards the message to it's parentViewController and closes the modal just the same as the first way. Neither makes a difference with regards to the memory.
So what I do instead is use this method to close the view:
[[self.closetScroller subviews] makeObjectsPerformSelector: #selector(removeFromSuperview)];
[self dismissModalViewControllerAnimated:YES];
When I do that, I can see my Object Allocations decrease in Instruments. Prior to opening the closet view I have object alloc at about 1.85mb. When I open the closet it increases to 2.5 or so depending on how many outfit images are loaded into the UIScrollView. Then when I close the view without the above method it stays at 2.5 and increases the next time I open it. Although when using the above method that removes the outfit images from the scroller, my object alloc drops back down close the the 1.85mb. Maybe a little more which tells me it's hanging on to some other stuff also.
Also note that when looking at the object allocations, I do see the ClosetViewController object created and when I close the modal it's refrence is released. I can see it malloc and free the view as I open and close it. It's not retaining the view object itself. i'm so confused.
Not sure what to do here. I am not getting any leaks and I am releasing everything just fine. Any ideas would be great.
mark
I Noticed object alloc in instruments keeping a live reference to UIScrollView every time I opened modal window. So to fix, when allocating for my scrollview, I instead allocated a new UIScrollView object and assigned it to closetScroller and then released. This took care of the problem
I think you were simply not releasing closetScroller in the dealloc of your view controller.

Resources