Looking at the UIWebView docs, it says that
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
I'm creating a webview on the fly on a UITableView cell tap. I'm not sure how to do the "set delegate to nil" bit, since I don't track the UIWebView after its pushed to the navigation stack. I would have though that the UIWebView's dealloc method would be calling release on the delegate anyway?
Here's what I'm doing:
UIWebView *webView = [[UIWebView alloc] init];
UIViewController *viewController = [[UIViewController alloc] init];
// Start the webview loading, etc
...
// set the delegate
[webView setDelegate:self];
// Add the webview to the viewcontroller
[viewController setView:webView];
[[self navigationController] pushViewController:viewController animated:YES];
[webView release];
[viewController release];
I get the impression that I should write
[webView release];
[viewController release];
[self release]; // Releasing the delegate as per the docs.
But that seems kind of awkward, or have I interpreted it correctly?
No. webView doesn't release/retain it's delegate it only assign it
UIWebView.h :
#property(nonatomic,assign) id<UIWebViewDelegate> delegate;
You can check [self retainCount] before and after [webView setDelegate:self]
It'll be the same
Just spotted this, old now but maybe an answer will be useful to someone.
The docs are correct, you should set the delegate reference to nil before releasing the webview.
In your code example, you would subclass UIViewController, and in the subclass override the -dealloc method to include a nullify of the view delegate.
For example:
- (void)dealloc {
// Clear the webview delegate
self.view.delegate = nil;
[super dealloc];
}
HTH
Related
I want to know what notification would I get in my CustomView class when this view will be displayed on screen.
CustomView *customView = [[CustomView alloc] init];
[self.view addSubview:customView];
NewViewController *newController = [[NewViewController alloc] init];
[self.navigationController pushViewController:newController animated:YES];
and after some work I pop this viewController.
[self.navigationController popViewControllerAnimated:YES];
I want to know what method in CustomView class will be called when that view will appear again on the screen.
Actually I have an infinite loop animation in that CustomView and on pushing to nextController I have to stop that animation loop and after coming back I need to start it again.
UIView doesn't get
viewWillAppear
viewDidDisappear
etc
ViewController in which it's contained, however, does, so, in order to pass it to UIView you are to implement following method:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self.view.subviews objectAtIndex:0] viewWIllAppear]; // i assume your subview is the only one, otherwise you need to know the index, or have it as an ivar/property
}
Another idea - since you use your view a lot, i assume you do not recreate it. Let it be a property of your [[UIApplication sharedApplication] delegate]. Now you can access it like this:
#define SharedView [(appDelegate*)[[UIApplication sharedApplication] delegate] sharedView];
Then make custom UIViewController and overwrite viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ( [SharedView.superview isEqual:self.view] )
{
[SharedView viewWillAppear];
}
}
You answered it yourself.
viewWillAppear
Have you looked at: UIView
Observing View-Related Changes
– didAddSubview:
– willRemoveSubview:
– willMoveToSuperview:
– didMoveToSuperview
– willMoveToWindow:
– didMoveToWindow
I have a TableViewController which is supposed to load a ViewController with a WebView in it when I select a cell.
Here's the code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PostViewController *postViewController = [[PostViewController alloc] initWithNibName:#"PostViewController" bundle:[NSBundle mainBundle]];
[postViewController.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.fr"]]]
[self.navigationController pushViewController:postViewController animated:YES];
[PostViewController release];
}
The problem is that the ViewController is loaded but nothing happens in the WebView.
When I debug the program I can see that the WebView's address is 0x0 so I guess something's wrong.
Is it because I try to modify the content of the WebView before its parent ViewController is loaded ?
I guess another way to do it properly would be to pass the URL to the ViewController and then to call loadRequest on the WebView from inside the viewWillAppear method.
But I need to understand why it doesn't work this way.
Try this
Instead of accessing the WebView why dont you just pass the URL value to the ViewController and load the Webview in the viewDidLoad of postViewController.
In your case
PostViewController *postViewController = [[PostViewController alloc] initWithNibName:#"PostViewController" bundle:[NSBundle mainBundle]];
postViewController.urlString = #"http://www.google.fr";
[self.navigationController pushViewController:postViewController animated:YES];
[PostViewController release];
In your postViewController.h declare the urlString with properties and synthesize in the .m file
Now in your viewDidLoad
//Alloc init your webview here
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
0x0 is the address of nil, meaning that your web view has not been initialized at this point.
If you're creating your web view in the loadView or viewDidLoad methods of PostViewController, then calling setNeedsLayout immediately after initialization will force its creation:
PostViewController *postViewController = [[PostViewController alloc] init ...
[postViewController.view setNeedsLayout];
Otherwise, these methods will not be called until your view is displayed.
I have created a view and assigned the view to viewcontroller
UIView *newView=[[UIView alloc] initWithFrame:CGRectMake(0,0,320,460)];
in viewDidLoad method I have assigned the view to the viewcontroller
-(void)viewDidLoad{
self.view=newView;
//[view release]; In this case also the application crashing
}
-(void)dealloc{
[newView release];//IN this case also the application crashing.
[super dealloc];
}
The crash log is this.
how to release the newView? or else the viewcontroller itself will take care of releasing the newView.
In most circumstances you will do the following:
- (void) loadView {
// Don't call super here if you assign the view property
UIView *newView = [[UIView alloc] initWithFrame: [UIScreen mainScreen].applicationFrame];
self.view = newView;
[newView release];
// the view is now owned and retained by the UIViewController
}
Apple recommends you allocate the view, assign and release it in -loadView and don't worry about it in -dealloc. This is important in cases when your view may be purged under low memory conditions.
here is my code , i am trying to get from one view to another without any memory leaks.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
firstviewcontroller *first = [[firstviewcontroller alloc] init];
[window addSubview:first.view];
[self.window makeKeyAndVisible];
return YES;
}
-(IBAction)gotosecondview:(id)sender
{
secondviewcontroller *second = [[secondviewcontroller alloc] init];
[self.view addSubview:second.view];
[second release];
}
-(IBAction)gotofirstview:(id)sender
{
[self.view removeFromSuperview];
}
to make the above code work without crashing , all i have to do is remove [second release].
if I remove it I get memory errors (build and analyze) . how can i solve this problem. and i dont want to use [self.navigationController pushViewController:second animated:YES];
all i am trying to do i navigating from one view to another and vice versa WITHOUT using navigation controller. my firstviewcontroller and secondviewcontroller are of type UIViewController.
Thanks in advance.
You need to keep the current view controller alive while its view is showing (so it can process the user input, etc.).
In your code, you can achieve that in several ways:
Keep an instance of firstviewcontroller and secondviewcontroller as instance variables, and release them on the dealloc method.
Keep an instance variable with the currently in use UIViewController and release it when you switch to another view.
The code for the second option would look something like this:
#interface
UIViewController *currentViewController;
#end
#implementation
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
firstviewcontroller *first = [[[firstviewcontroller alloc] init] autorelease];
[self switchToViewController:first];
[self.window makeKeyAndVisible];
return YES;
}
- (void)switchToViewController:(UIViewController *)aViewController {
[currentViewController.view removeFromSuperview];
[currentViewController release];
currentViewController = [aViewController retain];
[self.window addSubview:currentViewController.view];
}
-(IBAction)gotosecondview:(id)sender {
[self switchToViewController:[[[secondviewcontroller alloc] init] autorelease]];
}
#end
Here, all the logic for maintaining a single UIViewController alive lies in the switchToViewController method, which also handles the logic for switching from one view to another. As an added bonus, you can quickly add support for animations by adding a couple of lines in switchToViewController.
You can not release view in the call.
There is only one thing you can do in such conditions. use Autorelease,
The reason [second release] is crashing your code is likely because you're releasing your view controller which in turn releases the second view. The iPhone cookbook has some sample code on switching/swapping views if that's all that you're trying to accomplish. Here's the link. Hope this helps!
link text
I encountered some strange memory leaks executing following code on iPhone device:
#implementation TestViewController
#synthesize myButton;
- (IBAction)buttonPressed {
ABPeoplePickerNavigationController* selectContactViewController = nil;
selectContactViewController = [[ABPeoplePickerNavigationController alloc] init];
selectContactViewController.peoplePickerDelegate = self;
[self presentModalViewController:selectContactViewController animated:YES];
[selectContactViewController release];
}
Releasing the picker simple done as follows:
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
[self dismissModalViewControllerAnimated:YES];
}
Instruments marks "selectContactViewController = [[ABPeoplePickerNavigationController alloc] init];" as leaking. Any idea why?
You might want to construct your Picker control like so:
ABPeoplePickerNavigationController* selectContactViewController = nil;
selectContactViewController = [[[ABPeoplePickerNavigationController alloc] init] autorelease];
selectContactViewController.peoplePickerDelegate = self;
[self presentModalViewController:selectContactViewController animated:YES];
When you present the modal view controller, it will retain the view on its own. That's how it's able to still pass you an instance of the view controller to your delegate. Best bet is to set the view controller to be autoreleased, so when it gets popped from the navigation controller, the NSAutoReleasePool will garbage collect it.
Just a comment - do you use any protocol like UINavigationControllerDelegate in the interface declaration?
I encountered a situation where just referencing this protocol caused a similar leak message.