removeFromSuperView is not working in iPad2 with iOS5 - iphone

I have a little issue from removeFromSuperView as it's not at least working with iPad2 with iOS 5. I'm displaying a custom UIView alert before my table populates with data and once done, I'm removing it from the super view. with every other device it's working fine except in iPad2 (iOS5). Am I missing anything?
.h
#private
SaveUIDisplayViewController *wbsSummaryLoadView;
.m
// Displaying
wbsSummaryLoadView = [[SaveUIDisplayViewController alloc] initWithNibName:#"SaveUIDisplayViewController" bundle:nil];
[[wbsSummaryLoadView view] setFrame:[self view].bounds];
[wbsSummaryLoadView setupSavingViewWithTitle:NSLocalizedString(#"Loading...", #"")];
[[self view] addSubview:wbsSummaryLoadView.view];
// Removing
[wbsSummaryLoadView.view removeFromSuperview];
[wbsSummaryLoadView release];
wbsSummaryLoadView = nil;

Once you add a view you can release it right away. (a copy is creating by using addSubview)
Try:
[[self view] addSubview:wbsSummaryLoadView.view];
[wbsSummaryLoadView release];
and then you don't need to care, because if you release whole view you release that added view as well.

You are storing two different objects. When you create the SaveUIDisplayViewController, you are declaring a new instance in that method. When you are removing it, you are using (I guess) the member variable.
SaveUIDisplayViewController *wbsSummaryLoadView = [[SaveUIDisplayViewController alloc] initWithNibName:#"SaveUIDisplayViewController" bundle:nil];
This will hide any declaration of wbsSummaryLoadView that you have defined in the header of the object.
And when you come to remove it
[wbsSummaryLoadView.view removeFromSuperview];
Has to have wbsSummaryLoadView declared somewhere so (this is where I'm guessing as you haven't posted your .h file) if this is declared in the header, then it won't be the same as the one when you created it (in fact it will probably be nil at this point)

Related

How "release" an UIWebView on ARC

I'm trying to developed a really simple browser to be part of an iPad app. That browser will have tabs. All tabs are based on a .xib with an UIWebView filling almost all .xib frame.
I store all them inside an NSMutableArray, called tabsArray.
So, here's how I add a new tab to the array:
declaration:
.h
#property (nonatomic,strong) NSMutableArray *tabsArray;
#property (nonatomic,strong) UIDetailWebController *pagina;
.m
self.pagina = [[UIDetailWebController alloc] initWithNibName:#"UIDetailWebController" bundle:nil];
[tabsArray insertObject:pagina atIndex:currentViewTag+1];
how I display it on screen:
[self.view addSubview:[[tabsArray objectAtIndex:currentViewTag+1] view]];
And, finally, here's how I'm trying to "release" the UIWebView when user closes a tab (with a specific index):
[[[tabsArray objectAtIndex:index] view] removeFromSuperview];
[[tabsArray objectAtIndex:index] setWebView:nil];
[[tabsArray objectAtIndex:index] setView:nil];
[tabsArray removeObjectAtIndex:index];
My problem is: It appears that by doing this I simply don't release it. Memory consumption keeps the same, and If I'm playing an youtube video, the audio continues to play.
I'm kind of new on programming, and started iOS development by iOS 5, with ARC, so probably I'm letting slide some basic detail related to memory management.
SOLUTION:
Ok, I found out that what was retaining webview was the implementation of PullToRefreshView (https://github.com/chpwn/PullToRefreshView). When I set it's delegate to nil; everything just works!
The property pagina is is a strong property, so it retains the value that you assign to it in:
self.pagina = [[UIDetailWebController alloc] initWithNibName:#"UIDetailWebController" bundle:nil];
So you should set it to nil:
[tabsArray removeObjectAtIndex:index];
self.pagina = nil; // Add this line.
Finally, not that the following lines may not be needed:
[[tabsArray objectAtIndex:index] setWebView:nil];
[[tabsArray objectAtIndex:index] setView:nil];
And that the line:
[[[tabsArray objectAtIndex:index] view] removeFromSuperview];
may be simplified into:
[self.pagina removeFromSuperview];
I think the problem is that you store all your UIDetailWebControllers in an array. The array is keeping a strong pointer to your DetailWebController.
You should use:
[tabsArray removeObjectAtIndex:index];
And then set
self.pagina = nil;
After calling [self.pagina removeFromSuperView]; it should work.

How do i properly discard a subview?

I have a problem with my app where the code for which is far too long to go into, but suffice to say when i'm removing a UIView and replacing it with a new one like so:
NSLog(#" .. %#", (Icon *)[self viewWithTag:index]);
Icon *icon = (Icon *)[self viewWithTag:index];
CGRect frame = icon.frame;
int tag = icon.tag;
[icon removeFromSuperview];
[icon release];
Icon *icon2 = [[Icon alloc] init];
icon2.frame = frame;
[icon2 makeIconStandardWithTag:(int)tag];
[self addSubview:icon2];
It does some weird thing where that NSLog the first time (because the view is already there) shows that the object is an icon, but the second time after running this code shows that it's a UIImageView for some reason now, and it displays what i presume to be the original icon at some odd position on the screen. It's very erratic behaviour. But what i do know is this:
Removing the [icon removeFromSuperview]; line, although keeping the object there, stops this behaviour and causes the NSLog to return an Icon, as it should.
So my guess is that it's not removing icon correctly. Is there a way to completely remove icon, or is removeFromSuperview as far as i can go. What i could do is just have it set to alpha = 0 but this is more of a patch-over solution and not how i want to solve it.
"Is there a way to completely remove
icon, or is removeFromSuperview as far
as i can go"
You can set the object to nil:
icon = nil;
Can you verify what "self" is in this line of code:
It might not be what you think.
[self addSubview:icon2];
NSLog(#" Self is %#", self);
This is a guess, but try setting self.tag to -1 or some other value that doesn't collide with the tags you're setting on your Icon objects. The viewWithTag: method searches the current view and its subviews for a match, so if self.tag == 0 and you call [self viewWithTag:0], you'll get self.
Did you retain icon somewhere prior to this? If not, no need to release it after the call to removeFromSuperview. Similarly, unless you need the reference to icon2 elsewhere, you can release that after calling addSubview.
Views retain views added via addSubview, and they release views removed via removeFromSuperview.

updating value of modal view variable

I'm trying to make a modal view which displays the champion of my app.
there's a NSMutableString variable called champ in modal view,
which is supposed to be updated by returnChamp function in main view.
the champ string is correctly set in main view,
but in modal view, the champ value appears as (null).
In fact, it seems it doesn't even go into the returnChamp function.
so apparently something wrong with my calling or implementing returnChamp,
but I have another function that does the similar, and that works fine.
could anyone please help me?
-(void) mainView{
.....
champ = [[currentPlayers objectAtIndex:playerIndex] retain];
NSLog(#"%#",champ);
modalWinner = [[winner alloc] init];
modalWinner.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:modalWinner animated:YES];
}
- (NSMutableString *) returnChamp{
NSLog(#"returnChamp");
return champ;
}
//in modalWinner
-(void) modalView{
..............
champName = [[NSMutableString alloc] init];
NSLog(#"%#", [(MainViewController *)self.parentViewController returnChamp]);
champName = [(MainViewController *)self.parentViewController returnChamp];
UIImage *champImage = [UIImage imageNamed:champName];
}
self.parentViewController is probably not actually a reference to your object. For some reason, it seems that the framework always insists on setting a UINavigationController as self.parentViewController - even for modals, and to the extent that it will create one if there isn't already one. This is probably going unnoticed because you're casting it to your MainViewController type.
You'll need to find a different way of making your original object available to be communicated with, or perhaps pass the appropriate value to the newly-instantiated controller before you present it.
For example, if you add a champName property to the modal class, you can do:
modalWinner = [[ModalWinnerViewController alloc] init];
modalWinner.champName = myValue; /* Set value before presenting controller */
[self presentModalViewController:modalWinner animated:YES];
There will probably be some code needed to update the UI with this value. The viewWillAppear method of the modal view controller is a good place for this as it is called by the framework immediately before the view is presented.
Note that this property-based approach could be used to keep a reference to your intended parent object, as well. And see here for a different approach to solving a similar problem.

iPhone loading view from nib only works once

I'm trying to add a «loader-view» to my app which shows a spinner while doing stuff.
This works fine the first time, but it doesn't work a second time.
here's what I do:
I have a viewController for the spinner (spinnerViewController) and a nib-file which I made in IB (spinner.xib).
I load the nib in the viewDidLoad-event:
spinnerView = [[spinnerViewController alloc] initWithNibName:#"spinner" bundle:nil];
[spinnerView retain];
spinnerView is declared in the .h-file (spinnerViewController *spinnerView;)
next, I show the spinner-view:
[self.view addSubview:spinnerView.view];
[self.view bringSubviewToFront:spinnerView.view];
which works fine...
And now the trouble starts. No matter what I do, I can't show the spinner view again.
I tried just hiding it (self.view sendSubViewToBack: spinnerView.view) which works for hiding, but when I try to bring it to the front again (self.view bringSubViewToFront: spinnerView.view) it doesn't work.
I also tried removing the spinner-view and add it again with no success (within the spinnerViewController: [self.view removeFromSuperview] and to show it again [self.view addSubview... )
[EDIT]
I changed the whole setup a little and just made the spinner-view a subview in IB - again, hiding works, but showing again fails.
What I found out: After the bringSubViewToFront-command, I call some web-service to get some data. When I comment the following code out and just show the spinnerView, it works. So now I'm trying to figure out how to determine when the spinner-view appeared and then continue with the code - but naturally, this doesn't work (yet) :)
Any ideas what I'm doing wrong??? ;)
Problem solved.
This page gave the answer: http://urenjoy.blogspot.com/2009/05/uiactivityindicatorview.html
Apparently, the update has to happen in a separate thread, as the web-stuff blocks the current one, hence the view did not appear.
[NSThread detachNewThreadSelector:#selector(doWork) toTarget:self withObject:nil];
- (void) doWork {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
.....Time Consuming Code here .....
[pool release];
}
I might be not exactly on your question, but in general creating a ViewController class in order to show a spinner on the screen is a huge overkill ... just try to discover the logic behind what you do : you create a viewcontroller, but you never use it, you use the view.
So in short I believe you need only a UIView (the view property of the UIViewController)
Why don't you try something like :
... in your class interface...
UIActivityIndicator* activity;
... when the activity needs to happen ...
activity = [[UIActivityIndicator alloc] initWithActivityIndicatorStyle: ....
[activity startAnimating];
[self.view addSubview:activity];
[activity release]
... when the activity is finished
[activity removeFromSuperview]; //this will also decrease the retain count

Problem releasing object using "removeFromSuperView" iPhone

I have this concrete problem, but if You find my initial design idea crazy and have a better suggestion, please let me know:)
I have a UIView that acts as a container/background for adding other views. The important thing is that only one view is present at a time. So before doing any adding of views I do this:
for(UIView *v in [self.currentView subviews]) {
[v removeFromSuperview];
}
self.currentView is the view I add my subviews to.
After this I add a new UIView in this manner:
UIView *tempView;
switch (self.currentIndex) {
case 1:
tempView = [[AView alloc] initWithFrame:frame];
[self.currentView addSubview:tempView];
[tempView release];
break;
case 2:
tempView = [[AView alloc] initWithFrame:frame];
[self.currentView addSubview:tempView];
[tempView release];
break;
default:
break;
}
This way I remove all views, since I release the tempView straight after I add it to
the self.currentView I end up with a retain count of one on the the UIView currently living
in the currentView.
This all seems fine, but as I look at it with Instruments I can see that each time I run the above code a new AView object is allocated and the old one keeps hanging around with a retain count of 1, either I am missing some obvious retain action being performed on my object or else the "removeFromSuperView" does not call "release" on my view.
In real life my objects are not of type AView, but of many different types, but this way I can test if there is always only one AView instance allocated.
As I can read from the documentation "removeFromSuperView" should call "release" on the view so I am a bit confused as to why my Views are not deallocated.
Again, maybe I am going about this the wrong way and suggestions are really welcome.
The setup is that there is a number of button at the bottom of the screen and when the user clicks on the view changes.
Thanks for any help or pointers given:)
You are iterating a collection and simultaneously changing it
Try
while ([self.currentView subviews].count>0) {
[[[self.currentView subviews] objectAtIndex:0] removeFromSuperView];
}
instead.
you could try the "bringSubviewToFront" and "sendSubviewToBack" functions instead of creating a new UIView everytime. That ways, you won't be creating uiviews for every action and therefore be less pressing on the memory consumption of your application.