I have this property called mySegmented, declared like this
.h
#property (retain) UISegmentedControl *mySegmented;
.m
#synthesize mySegmented = _mySegmented;
then, it was created like this:
self.mySegmented = [self createSegmented];
// createSegmented creates an autoreleased segmented control
My app has 3 different segmented controls. Just one appears at a given time.
At some point of my app, I have to hide one particular segmented control, so, what I do is to build an array of all segmented controls and iterate... this is inside a block.
[UIView animateWithDuration:0.8
animations:^{
NSArray *list = [NSArray arrayWithObjects:
self.mySegmented1,
self.mySegmented2,
self.mySegmented3,
nil];
for (UISegmentedControl *oneSeg in list) {
[oneSeg setAlpha:0.0f];
}
}];
what happens is: after some time, the app crashes while trying to build this array. I suppose one of the segmented controls is deallocated somehow. No deallocation that I can see in code.
My question is: this array being created is autoreleased. What happens when the block finishes the animation? is a release sent to each member of the array?
If I retain the segmented control after creating it, Xcode complains it will leak.
any clues?
thanks.
Please retain like you tried, but make sure to release them in the dealloc method, Xcode should not complain that way.
Your array is also autoreleased inside the block but that's fine, the array doesn't own the references inside of it, the real problem is the segmented controls not being retained by your view controller.
Let me know how it goes.
Related
I have a NSDictionary, storing value by parsing. I am allocating and storing value in -viewDidLoad. And accessing the values in -viewWillAppear. It works perfectly fine.
Then, I have UIPageControl with UIScrollView. While scrolling the UIScrollView, again I am accessing the same dictionary, it crashes saying
[CFString respondToSelector:]: send to deallocated....
- (void) viewDidLoad {
[super viewDidLoad];
scoresDict = [[NSDictionary alloc] initWithDictionary:[scoreObj scores]];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0)
return;
if (page >= kNumberOfPages)
return;
NSLog(#“scoresDict %#”,scoresDict);
}
I tried using retain in the same function, it didn’t work out. And copy, it also didn’t work. Any help would be appreciated. Thanks!
You don't say so, but it looks like all of these methods are being called from an instance of your custom UIViewController or UIScrollViewController subclass.
The most likely problem is that this instance itself isn't being retained.
When you first load the view from the nib, both -viewDidLoad and -viewWillAppear are called. It's possible, however, that garbage collection is happening in between those calls and your call to -loadScrollViewWithPage, and that no object has any connection to the view controller instance itself.
If that's the case, using copy or retain on the scoresDict won't solve the problem. You need to make sure that you are copying or retaining the view controller instance itself. Figure out what object needs to be retaining your view controller and make sure it is being retained.
A quick way to test whether this is the problem or not: create a "myViewController" property in your application delegate. In viewDidLoad, add a line:
[[[UIApplication sharedApplication] delegate] setMyViewController:self];
If this fixes your problem, it means the problem was the view controller getting released. That doesn't mean this is your best solution, though--it's just a diagnostic. You need to figure out what should be retaining your view controller and make sure it does so.
When displaying an item such as a button in a ViewController, I declare it in the header file:
#property (nonatomic, strong) UIButton *startButton;
Synthesize it in the implementation file:
#synthesize startButton;
Initiate it in the implementation file:
startButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
And set the reference to nil in viewDidUnload:
[self setStartButton:nil];
However, what if I have 60 listed items (in a UIScrollView) which are created dynamically in a loop, in viewDidLoad (fed from Core Data)?
(Not using TableView, because the items are quite complicated and interactive.)
Should I declare the items anywhere first? Should I set them to nil anywhere? (Or should I just keep my fingers crossed and pray to the Arc?)
Some guidance would be appreciated. Thanks.
Does your view controller have properties or instance variables that point to each of those 60 items?
Yes: Then set those ivars or properties to nil in your -viewDidUnload.
No: Then there's nothing to worry about.
ARC changes what you do to manage memory, but it doesn't change the basic philosophy, which is that every object should take care of its own references to other objects but not worry about anybody else's.
In this case, the view that contains all those items will have strong references to the items (via it's array of subviews). When the view controller releases its view, that view will then be deallocated and release all its subviews in the process. So all those items will be taken care of. If you did have strong references to any of those items, those references will prevent the referenced objects from being deallocated -- setting the references to nil will avoid that.
If you are creating these views on the fly and adding them as subviews of the scrollView, then you don't need to do anything else.
When the scrollView is released during -viewDidUnload, it will properly clean up all its subviews.
Update
Think of it this way. In a normal view setup on a storyboard, you don't need have a property for every view, only the views your controller interacts with. This is basically the same thing. You have a bunch of views that are embedded into a superview. If the controller doesn't interact with them, then you don't need to worry about them.
no. :)
you definitely set the all pointer to nil what are not necessary anymore when you are using the ARC.
the ARC will release the memory of the current object when there is no more strong pointer who tries to keep alive the object. if you don't set them to nil the ARC thinks you are still using them and they will be in the memory and they will cause serious memory leak.
UPDATE #1
if you have any reference for the buttons this is the easiest way to do it, you don't need to do set to nil anything, because their superview class retain them and you should just remove from their superview.
for (UIView *_subView in self.view.subviews) {
if ([_subView isKindOfClass:[UIButton class]]) {
[_subView removeFromSuperview];
}
}
if you're storing their pointer any other place (in an NSArray for ex.) you must have to remove the pointers from them as well.
In my iPad App,
I have one custom class inherited from UIButton.
I am adding the buttons on my main view dynamically using for loop.
This button has also has label.
My problem is when to release the Custom Class's Objects.
for(NSMutableDictionary *dict in Categories)
{
Category *category=[[Category alloc] initWithName:[dict valueForKey:#"category_name"] identity:[[dict valueForKey:#"category_id"] intValue] imageName:nil];
category.lblimagesCount=[[UILabel alloc] initWithFrame:CGRectMake(category.frame.size.width-31, category.frame.origin.y-42, 26, 26)];
[category addSubview:category.lblimagesCount];
[self.viewHeader addSubview:category];
[category release];
category=nil;
}
How to avoid memory leaks.
Especially for
1. labels
2. Category class.
Where to write release ?
i. Category class(UIButton) has its dealloc method but it is never called.
ii. As I am releasing it immediately after adding it to the subview , Will it affect my button click.
iii. When should I release the labels.
Very confused about the memory management.
I'll answer your questions:
i. Category class(UIButton) has its dealloc method but it is never called.
Because its not totally released, see question ii.
ii. As I am releasing it immediately after adding it to the subview , Will it affect my button click.
No, because your subview is now the owner of the button, when you add it to the subview, both you and the subview are owners, when you release, the button now is owned by the subView.
iii. When should I release the labels.
As soon as you add then to the subview, for the same reason as the question ii.
I'll be happy to clarify if you dont understand it.
I am having an iphone app with admob on two screens's viewdidLoad
My code is:
AbMob =[[GADBannerView alloc]initWithFrame:CGRectMake(0.0,self.view.frame.size.height-195, 320, 50)];
AbMob.adUnitID = AdMob_ID;
AbMob.rootViewController = self;
[self.view addSubview:AbMob];
GADRequest *r = [[GADRequest alloc] init];
r.testing = NO;
[AbMob loadRequest:r];
Problem is this code works fine on one screen but crashes on other screen with error
* -[GADOpener didOpen]: message sent to deallocated instance
0x6074750
Can anybody tell me what could be the problem
You have a retain/release problem somewhere in your code. You say it works in one view, but not another - this makes me believe that you are storing this instance outside of your view controllers. The message sent to deallocated instance issue is due to you trying to use a variable that has been removed from memory somewhere in the code before this error pops up. You need to ensure that the view controller that is creating this object is properly retaining it so that it does not get deallocated before you need to use it again with:
GADBannerView *_adMobBannerView;
#property(nonatomic,retain) GADBannerView *adMobBannerView; //view controller retains object when using self.adMobBannerView = bla
It sounds like you may need to brush up on your memory management documentation, but the gist of it is that anywhere you are calling alloc, you are managing that memory and need to call release when you are done with it. If you need a variable to stick around for longer than an autoreleased object is living for, then you need to create an instance variable and retain the object yourself with ivar properties #property (nonatomic, retain).
I kind of understand why I'm getting this analyzer warning. Because I'm using an object that is being passed in. I've tried autorelease and retain however these cause me other problems like unrecognized selector sent to instance.
The aim of my CommonUI function is to re-use code, but I have to cater for addSubView and presentModalViewController.
Perhaps I'm doing some obvious wrong ?
Change your code like this:
HelpViewController *helpvc = [[HelpViewController alloc] init....];
[vw addSubview:helpvc.view];
[helpcv release];
I think you don't need to pass the other VC.
There are two problems here.
First, if you call [vc release] (as the other answers suggest), you'll certainly make the analyzer happy but likely crash the app. A view controller's view doesn't retain the controller, so any button targets in the view will be pointing to garbage.
You will need to somehow keep the HelpViewController retained for as long as it is showing up onscreen. The "parent" view controller should likely retain it somehow. You could autorelease it, and return it. Then whomever calls showHelpClick... would retain the returned controller.
Second, you don't need to have the (UIViewController *)vc passed in as an argument.