I have a not usual architecture. With one UIViewController and many subview's. I use UIView like viewController and UIViewController for transition animation.
UIView with many subview, which i push on main window, i removeFromSuperview and all ok, but subview not call dealloc method. Also i try to clean objects
- (void) dealloc {
NSLog(#"ActivityShowVC dealloc");
[showView removeFromSuperview];
showView = nil;
}
This called.
- (void) dealloc {
NSLog(#"ActivityShowView dealloc");
[mainScroll removeFromSuperview];
[titleView setDelegate:nil];
[titleView removeFromSuperview];
titleView = nil;
[photoView setDelegate:nil];
[photoView removeFromSuperview];
photoView = nil;
[predictionView setDelegate:nil];
[predictionView removeFromSuperview];
predictionView = nil;
[calendarView setDelegate:nil];
[calendarView removeFromSuperview];
calendarView = nil;
[descriptionView setDelegate:nil];
[descriptionView removeFromSuperview];
descriptionView = nil;
}
But this have some problem.
If dealloc is implemented and not called then there is something retaining the instance. You need to rethink the strong references to it.
Dealloc is not a good place to do anything other than releasing resources since the instance is no longer fully functional nor in a complete state. Doing things like: [showView removeFromSuperview]; are best done explicitly prior to deallocation.
As #Greg stated, most or all of what you are doing in dealloc is not needed under ARC. Subviews are now generally weak so no explicit dealloc is necessary. In fact they may be already gone depending on the order of the teardown of the view hierarchy.
I have solved a similar problem. In my Viewcontroller, I have a NSTimer pointer created, when I put the code below in 'viewWillDisappear', 'dealloc' is called.
if (_timer) {
[_timer invalidate];
_timer = nil;
}
Related
In My Application i need to release my NSTimer , when i am moving from one view controller to another view controller . How to release this type of objects in ARC ? i am using below code for creation and releasing NSTimer but Where i have to write this releasing code in view controller?
For Creation.
- (void)viewDidLoad{
[super viewDidLoad];
updateBCK = [NSTimer scheduledTimerWithTimeInterval:(5.0) target:self selector:#selector(changeImage) userInfo:nil repeats:YES];
[updateBCK fire];
}
-(void)changeImage{
static int i=0;
if (i == [myImages count]){
i=0;
}
[UIImageView beginAnimations:nil context:NULL];
[UIImageView setAnimationDuration:0.6];
mainBackgroundImageView.alpha=1;
mainBackgroundImageView.image =[myImages objectAtIndex:i];
NSLog(#"\n The main screen image is %#",[myImages objectAtIndex:i]);
[UIImageView commitAnimations];
i++;
}
For Release.
[updateBCK invalidate];//
updateBCK = nil;
Thanks in Advance.
You should call
[timer invalidate];
timer = nil;
where you push your view controller. If this is an issue, you can still call it in
- (void) viewWillDisappear:(BOOL)animated;
Also, you should initialize it in
- (void) viewDidAppear:(BOOL)animated;
That makes more sense.
When you want to stop time
use below code
[timer invalidate]; // timer is the name of timer object
- (IBAction)button:(id)sender {
SecondViewController *second = [[SecondViewController alloc]
initWithNibName:#"secondViewController"
bundle:nil];
[self presentViewController:second animated:NO completion:nil];
[self.timer invalidate]; // timer is the name of timer object
timer=nil;//it may work without this line too ;not sure
}
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Timers/Articles/usingTimers.html
A timer maintains a strong reference to its target. This means that as long as a timer remains valid, its target will not be deallocated. As a corollary, this means that it does not make sense for a timer’s target to try to invalidate the timer in its dealloc method—the dealloc method will not be invoked as long as the timer is valid.
when i am moving from one view controller to another view controller
Then you should do this in delloc, if you want to do some cleanup tasks when your view is dismissing or released. It's the best place, In such case you can implement it.
-(void)dealloc{
[updateBCK invalidate];//
updateBCK = nil;
}
Hope this helps
find a strange code here
I have a viewcontroller, it has an array with books, and click the cell, then push to a detailViewController, detailVC has a variable infoDict,
#property (nonatomic,retain) NSMutableDictionary * infoDict;
navigationController push
DetailViewController * tDVC = [[DetailViewController alloc] init];
tDVC.infoDict = infoDict;
[self.navigationController pushViewController:tDVC animated:YES];
[tDVC release];
tap the back button, pop back, and inside dealloc of DetailVC
-(void)dealloc
{
[super dealloc];
NSLog(#"before %d",infoDict.retainCount);
[infoDict release];
}
but when I tap back, in this dealloc app crashes randomly, EXC_BAD_ACCESS.
when move [super dealloc] to the bottom of dealloc, it seems back to normal.
pls help me to understand this , many thanks
[super dealloc] deallocates the object itself. If you type dealloc and let Xcode autocomplete, you get this:
- (void)dealloc
{
<#deallocations#>
[super dealloc];
}
Meaning you should release objects and properties before you call [super dealloc]
Your -dealloc implementation is out of order. The call to -[super dealloc] must be the absolute last invocation in the dealloc method. When you access the ivar infoDict, the compiler is really doing something like self->infoDict and by this point, self has been deallocated and is no longer valid.
If at all possible, I recommend using ARC instead of manually managing memory.
Try
its better if you use self.infoDict = nil; instead of [infoDict rlease];
-(void)dealloc
{
NSLog(#"before %d",infoDict.retainCount);
[infoDict release];
[super dealloc];
}
I'm building a Cocos2D game in which after two certain sprites collide (by simple bounding box technique), I call
[[CCDirector sharedDirector] replaceScene:gameOverScene];
to change to the game over scene.
Once it initializes the game over scene with everything in it, the game crashes and goes to this method in ccArray.m class:
void ccArrayRemoveAllObjects(ccArray *arr)
{ while( arr->num > 0 )
CC_ARC_RELEASE(arr->arr[--arr->num]);
}
with the message:
Thread 1: Program received signal: "EXC_BAD_ACCESS".
I tried to debug using breakpoints and figured out that once my gameOver scene gets initialized and ready to display, the dealloc method in the previous class (the gameplay class, which called the replace scene) gets called and after which it throws this error.
My update method:
-(void)update:(ccTime)dt
{
if (CGRectIntersectsRect(plane.boundingBox, enemy.boundingBox)) {
CCScene *gameOverScene = [GameOverLayer sceneWithWon:NO];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
} }
My dealloc method:
- (void) dealloc
{
[super dealloc];
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil; }
I have no clue why this is happening. Please help.
Thanking you in anticipation.
You are calling super's dealloc before you are deallocating your gameplay scene.
Call super's dealloc at the end of your dealloc method :
- (void) dealloc {
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil;
[super dealloc];
}
When you are calling super's dealloc first you are releasing your instance making it members invalid so accessing them after the dealloc will create memory bad access issues
because you didn't show enough code,i can only guess that some of these objects,such as _monsters,mole,text,mBG1,mBG2,were autoreleased before you release them in the dealloc funtion.So,they can not be released anymore.This is concerned ARC-automaic reference counting which you should know, it's basis of ios.
try this only:
- (void) dealloc {
[super dealloc];
}
My app is crashing while releasing view controller object.
Here is my code.
TagCloudWebViewController *controller=[[[TagCloudWebViewController alloc]init]autorelease];
controller.htmlString=[[notification userInfo] valueForKey:#"url"];
[self.navigationController pushViewController:controller animated:YES];
This is my code from wheny above method is called
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(openTextInWebview:) name:#"kTouchTextUrl" object:Nil];
}
and
#pragma mark - UIGestureDelegate
- (void)longPressRecognized:(UILongPressGestureRecognizer *)longPressRecognizer {
CGPoint touchPoint = [longPressRecognizer locationInView:self];
NSArray *subviews = self.subviews;
for (int i=0; i<subviews.count; i++) {
TagView * tagLabel = (TagView *)[subviews objectAtIndex:i];
if ( CGRectContainsPoint( [tagLabel frame], touchPoint ) ) {
NSArray*objectArray=[[[NSArray alloc] initWithObjects:tagLabel.customLink, nil] autorelease];
NSArray*keyArray=[[[NSArray alloc] initWithObjects:#"url", nil] autorelease];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objectArray forKeys:keyArray ];
[[NSNotificationCenter defaultCenter] postNotificationName:#"kTouchTextUrl" object:nil userInfo:userInfo];
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString: tagLabel.customLink]];
break;
}
}
}
and this is notification method
DidLoad method
- (void) viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
_webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
_webView.scalesPageToFit = YES;
[self.view addSubview:_webView];
[self initSpinner];
if (htmlString) {
[self openURL:[NSURL URLWithString:htmlString]];
}
}
WebView delgate method
-(void) webViewDidStartLoad:(UIWebView *)webView {
self.navigationItem.title = #"Loading...";
[spinnerView startAnimating];
isLoading = YES;
}
-(void) webViewDidFinishLoad:(UIWebView*)webView {
self.navigationItem.title = [_webView stringByEvaluatingJavaScriptFromString:#"document.title"];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
-(void) webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
[self webViewDidFinishLoad:webView];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
(void) openURL:(NSURL*)URL {
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:URL];
[_webView loadRequest:request];
}
Update: The following answer was in response to the original question of why the UIViewController with a UIWebView was not appearing. The OP's original theory was that it was related to some problem regarding the premature releasing of the view controller object. But, as outlined in my answer below, I suspect the problem was related to the creation of the view controller itself. Anyway, my answer to the original question follows (but it unfortunately has nothing to do with the revised question):
I personally don't suspect the problem has anything to do with the
releasing of the controller. I think it is in the creation of the
controller's view. There's nothing in the above code that causes the
object to be released, so you problem rests elsewhere and you need to
show more code. If you're concerned about your notification center
stuff, try bypassing it and just add a button that does your
TagCloudWebViewController alloc/init, sets htmlString and pushes,
and see if that still causes your program to crash, which I suspect it
will.
I notice that you're creating your controller via alloc and init,
but not initWithNibNamed. According to the UIViewController Class
Reference:
"If you cannot define your views in a storyboard or a nib file,
override the loadView method to manually instantiate a view
hierarchy and assign it to the view property."
So, bottom line, either use a NIB, use a storyboard or define a
loadView. Defining a viewDidLoad doesn't preclude the need for a
loadView. You need to create a view for your controller, which is
done for you if you use NIB or storyboard, or you have to do manually
via loadView, if you don't use NIB or storyboard.
See
iPhone SDK: what is the difference between loadView and viewDidLoad?
for a discussion of the differences between viewDidLoad and
loadView.
I don not see any thing that causing crashing.I think you have changed your question.As per question you not using ViewController any where.Please show more details.
Updated: Please check, you are creating autoreleased object, it might be you are releasing some where by mistake.Try to avoid autoreleased object as it remain in the Pool and later releases ,which may causes a memory issue for you.
The above problem is occurs due to WebView delgate. After pressing back button the reference of the object is deallocating from memory due to this app is crashing while releasing the viewcontroller object. I did some thing like
-(void) viewDidDisappear:(BOOL)animated{
if([_webView isLoading]) {
[_webView stopLoading];
}
[_webView setDelegate:nil];
}
due to above code my crashing has been resolved
- (void)fadeOutSplash {
UIImageView *splash = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default-Landscape~ipad.png"]];
[self.window.rootViewController.view addSubview:splash]; // <-- OBJECT IS BEING RETAINED HERE
[UIView animateWithDuration:0.5
animations:^{
splash.alpha = 0;
}
completion:^(BOOL finished) {
[splash removeFromSuperview];
}];
}
I think ARC is retaining my "splash" when I add it to the subview of the rootViewController. ARC should release "splash" when I run my animation completion because it removes my "splash" from it's own super view. However, I can see in the allocation instruments that this parent view controller is staying allocated and it shows the problem line being where splash is added to the rootViewController. What can I do to make sure "splash" is released?
I fixed this problem, but I'm not exactly sure how.. Here's the likely solution:
- (void)removeFromSuperView
{
// Use this space to manually release any non IB pointers / variables as needed
self.someDictionaryIMadeInInit = nil;
while(self.subviews.count > 0) [[self.subviews objectAtIndex:0] removeFromSuperView];
[super removeFromSuperView];
}
This a little trick I came up with for ARC related views. I recommend it more as a last resort because truly this should be solved the appropriate way, but it's worth a try to save you from tearing out your hair!