i am using addSubView method to add views. Did any alternative methods are there for viewWillDisappear? viewWillDisappear is not firing. I want to release all allocated objects when the current view get dissapear. Currently i am using dealloc method to do this. But dealloc method is firing not quickly. Since i am getting memory warings and sometimes the my app may crash itself. The main problem is with voice files.
addSubview/removeFromSuperview (these methods relate with views not view controllers) doesnt call viewWillAppear/viewWillDisappear methods. You should write release object code in dealloc() itself.
removeFromSuperview should call dealloc().
You can try to release objects in method viewDidDisappear. Then you won't wait for firing method dealloc.
Also in method viewDidDisappear you can try to remove all subviews from superview (that will call viewWillDisappear to all subviews):
NSArray *subviews = [self.view subviews];
for (UIView *view in subviews)
[view removeFromSuperview];
release objects in viewDidUnload/viewDidDisappear and set to nil in dealloc
this might work, but you should surely look why viewWillDisappear is not called.
Related
I have a UIView subclass called ToolbarView that sort of acts like a floating window and has a UIToolbar that has an "X" button that can make the window disappear. My question is, is it possible for the object to delete itself from within its own class?
For instance, within ToolbarView.m, I have a method closeButtonPushed which fires when the X button is pushed. Is it as simple as to remove the view from its superview, and then call dealloc? Is it even necessary to call dealloc as once it is removed from the superview there won't be any other pointers to it. Or is this bad memory practice?
Yeah, don't call dealloc ever. If the superview is the only object that has a reference to your view, removing the view will cause its retain count to go to 0, and the runtime will then deallocate the object for you.
What you have to do is in closeButtonPushed method is, call
[self removeFromSuperView];
it will remove the ToolbarView object and IOS will call the dealloc method and release objects. No need to call dealloc manually.
Hey,
I'm adding a UIViewcontroller as a subview of my current view. With something like that:
[self.view addSubview:viewcontroller.view];
The user can interact with that added viewcontroller so I can't just release it after I added it's view as my subview, right ?
So I would like to release it the dealloc methode and set it to nil in viewDidUnload when my master viewcontroller gets unloaded, right ?
The problem is, the viewcontoller I add as a subview is not added every time. So the question is, how can I ceck if the viewcontroller was added as subview and if so, release it.
Thx a lot !
Sebastian
You can check it like this:
if(viewController)
{
[viewController release];
viewController=nil;
}
and yes u need to put this in your dealloc method.
If you read correctly your code:
[self.view addSubview:viewcontroller.view];
it is not the controller which is being added as a subview, rather the view it manages.
This is an important point, since it means that the controller itself does not get retained. What is retained is the view.
So you can simply go on releasing your viewController in -dealloc as usual:
-(void)dealloc {
[viewController release]; viewController = nil;
...
}
and in your viewController's dealloc you will need to release the managed view, if you allocated it manually (or wherever it makes sense for your controller to release its view, if necessary).
On the other hand, whenever your superview is deallocated, then also the view you added as a subview will be released (as per Apple spec of addSubview behavior). So nothing to worry about here. Just release the viewController properly (and make that the view controller manages correctly tis own view).
One more note: you should not release your view controller in viewDidUnload.
In some open source code that I used to contribute to, we had a macro called RELEASE_TO_NIL which did exactly this.
#define RELEASE_TO_NIL(obj) if(obj != nil) { [obj release]; obj = nil; }
You would use it like this:
RELEASE_TO_NIL(viewController);
Simple as that.
Just add an tag to viewController.view and test if self.view contains that tag.
UIView *testView = [self.view viewWithTag:yourTag];
if(testView!=nil){
doStuff;
}
According to the Apple docs, a UIViewController instance should manage a view that fills the whole screen. If your view does not fill the screen, you could either subclass UIView to handle delegation or make the superview work as a delegate.
Also, the subviews of a view are contained in an instance of NSArray, do [myView subviews] to return this property. Ask the returned array if it contains the subview in question and you can release accordingly.
But, without knowing more, it does sound like you need to rethink how you're setting all this up.
I need to release uiimage/view/subviews when I want, and have a few questions regarding proper practice of releasing them.
[imageView removeFromSuperview] would release the imageView and imageView.image?
view = nil; would release its subviews/and associated uiimages recursively? if not, should I implement a recursive function to release a view's subviews?
Thank you
Edit.
I looked at UIView's library reference
addSubview --
This method retains view and sets its
next responder to the receiver, which
is its new superview.
removeFromSuperview --
If the receiver’s superview is not
nil, the superview releases the
receiver. If you plan to reuse a view,
be sure to retain it before calling
this method and release it again later
as appropriate.
still not sure [imageView release] releases uiImage associated with it,
and would I still need recursive releasing of subviews. ie a view's getting dealloced would automatically guarantee it's subviews release?
[imageView removeFromSuperview] would
release the imageView and
imageView.image?
removeSuperView calls release on the view, but you should pay attention to the views retain count. Just because you called removeFromSuperview doesn't mean it's doing what you want.
view = nil; would release its
subviews/and associated uiimages
recursively? if not, should I
implement a recursive function to
release a view's subviews?
No, you probably want to do (depending on how you've managed your subviews during their creation. If the superview was their only reference, they likely have a retain count of 1 and therefore calling release after calling removeFromSuperview will result in an error):
for (UIView* subview in view){
[subview removeFromSuperView];
[subview release]
}
[view release];
EDIT: To answer your final question, no, calling release on a view does not automatically call release on all of its subviews. You have to do it yourself, whether with release or with removeFromSuperview.
When you do [imageView removeFromSuperview], it won't release anything. You need to so [imageView release] afterward. Even so, you still need to put your memory releasing for that view in imageView's dealloc.
I have a UIView in a UIViewController to which I add a custom subview in the viewDidAppear method.
MyView *myView = [[MyView alloc] initWithLabelText:text];
[self.view addSubview:myView];
[myView release];
The text variable is a string used on a label in myView. This text changes every time you come back to the current view. But it seems that viewDidAppear does not reload the view - it rather loads a new view over the old one - so I have two labels over each other.
I tried to use viewWillAppear but it doesn't make any difference. I also tried to use [self.view setNeedsDisplay] - doesn't help. I also tried to make myView an instance variable, but it also didn't help.
What worked was to remove the view explicitly, when I declared it as an instance variable:
- (void)viewDidDisappear:(BOOL)animated
{
[_myView removeFromSuperview];
}
Although there is this workaround I would like to simply reset the view when getting back to it. Does anybody know how to do that? I would appreciate it ;)
Don't alloc and init the custom subview every time, only the first time viewDidAppear is called. Then retain it in a property for subsequent use.
The followings thing can ben considered.
viewDidLoad --> alloc and init your sub views
viewDidAppear --> update sub views
dealloc --> release sub views.
i am trying to get a subview to become firstResponder. my understanding is that this is done in its viewDidAppear method, like so:
- (void)viewDidAppear {
[self becomeFirstResponder];
}
while overriding canBecomeFirstResponder to return YES:
- (BOOL)canBecomeFirstResponder {
return YES;
}
however, when i insert the subview in its parent view's viewDidLoad method:
- (void)viewDidLoad {
subViewController = [[SubViewController alloc] init];
[self.view insertSubview: subViewController.view atIndex: 0];
[subViewController viewDidAppear: NO];
[super viewDidLoad];
}
(i call viewDidAppear manually, because it does not get triggered automatically), the subview does not become firstResponder.
why does the subview not become firstResponder? and how can i make it firstResponder?
thanks,
mbotta
btw, this is a rewrite of my original question:
i am trying to build an iphone app where a rootviewcontroller object manages two subviews, one of which should react to a user shaking his iphone.
after some digging, i concluded the subview must be made firstResponder in its view controller's viewDidAppear method. moreover, the canBecomeFirstResponder method should be modified to return YES.
so here's what happens: i instantiate the rootviewcontroller in the app delegate. in its viewDidLoad method, i tell it to addSubView firstViewController. all of this works just beautifully.
however, firstViewController does not react to any shaking. i sprinkled some NSLogs around and found that while we DO tell firstViewController in canBecomeFirstResponder to return YES, and while we DO tell it to [self becomeFirstResponder] in viewDidAppear, in actual fact, it is not the firstResponder.
so, my questions are:
1) does a subview actually need to be firstResponder in order to react to shaking?
a) if not, how does one make a subview react without being firstResponder?
2) how does one make a subview firstResponder?
what makes this interesting is that if i perform the same sequence (canBecomeFirstResponder, [self firstResponder], motionBegan:) in a different project with only one view controller, it all works flawlessly. clearly, i must be hitting a design flaw of my own making.
thanks,
mbotta
Not 100% sure, but this could be your problem. If we could see the offending methods it might be easier.
From the Event Handling Best Practices (emphasis added by me):
If you handle events in a subclass of
UIView, UIViewController, or (in rare
cases) UIResponder,
You should implement all of the event-handling methods (even if it is
a null implementation).
Do not call the superclass implementation of the methods.
If you call the superclass methods the events are probably getting passed along to the nextResponder.
EDIT
The Event Handling Best Practices link above is dead. I couldn't find that pull quote anywhere, but Event Handling Guide for UIKit Apps seems to be the most relevant.