I am new to iPhone development.
I am developing an application in which I am using Single tone class.
When I am creating an object of single tone class it is giving me memory leak on analyzing my code. It is giving message as "Potential leak of an object" and "Allocated object is not referenced later". But I am using that object in my code.
following is my code where I have created single tone class object
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Inside View");
self.navigationController.navigationBar.topItem.title = #"Menu List";
UIImage *image = [UIImage imageNamed:#"Navigation_bar.png"];
[_bgImage setFrame:CGRectMake(0,-45,320,510)];
[self.navigationController.navigationBar setBackgroundImage:image
forBarMetrics:UIBarMetricsDefault];
[self.tabBarController.tabBar setBackgroundImage:[UIImage imageNamed:#"Tab_bar.png"]];
[self.navigationItem setHidesBackButton:YES];
menuTableView.backgroundColor=[UIColor clearColor];
menuTableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
_hotelMenu=[SharedHotelMenu sharedInstanceMethod];
_queryFormatter=[[DatabaseQueryFormatter alloc]init];
_isSearchOn=NO;
_searchResult=[[NSMutableArray alloc]init];
_categorySearch.layer.cornerRadius = 19;
_categorySearch.clipsToBounds = YES;
_categorySearch.delegate=self;
UIView *_paddingView=[[UIView alloc] initWithFrame:CGRectMake(0,0,5,10)];
_categorySearch.leftView=_paddingView;
_categorySearch.leftViewMode=UITextFieldViewModeAlways;
[_paddingView release];
UIView *_paddingRightView=[[UIView alloc] initWithFrame:CGRectMake(0,0,30,10)];
_categorySearch.rightView=_paddingRightView;
_categorySearch.rightViewMode=UITextFieldViewModeAlways;
[_paddingRightView release];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(searchBar)
name:UITextFieldTextDidChangeNotification object:_categorySearch];
}
}
I have created single tone class object as _hotelMenu=[SharedHotelMenu sharedInstanceMethod];
As far as I can see in your code is that this line may cause memory leak
menuTableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
As this is #property(nonatomic, retain) UIView *tableFooterView and it will retain your object and thus retain count becomes 2.
Use this
UIView *footerView = [[UIView alloc] initWithFrame:CGRectZero];
menuTableView.tableFooterView = footerView;
[footerView release];
Related
I have created two view controllers in which there is UIImage animations.Its crashing frequently and showing memory leaks in xcode instrument.
My Controllers Code-
- (void)viewDidLoad {
NSArray *firstArray;
firstArray = [NSArray arrayWithObjects:
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"up0001" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"up0002" ofType:#"png"]],
::
::
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"up0035" ofType:#"png"]], nil];
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
imgView = UIViewContentModeScaleToFill;
[imgView setAnimationImages:firstArray];
imgView.animationDuration = 1.75;
imgView.animationRepeatCount = 0;
[imgView startAnimating];
[self.view addSubview: imgView];
}
- (void)dealloc {
[super dealloc];
[imgView release];
imgView = nil;
}
And I am changing viewcontrollers as my rootviewcontroller by getting appdelegate object and calling following appdelegate function in my Appdelegate.m(Please suggest any good approach)
- (void)changeRootViewController:(NSString *)controllerName
{
if(self.viewController){
[self.viewController.view removeFromSuperview];
self.viewController=nil;
}
if (controllerName == #"ViewController") {
ViewController *lviewController =[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
} else if (controllerName == #"MainViewController") {
// Use a different VC as roowViewController
MainViewController *lviewController =[[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
} else if (controllerName == #"SecondViewController") {
// Use a different VC as roowViewController
SecondViewController *lviewController =[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
}
[self.window makeKeyAndVisible];
}
And calling this in my respective controlers button pressed as -
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate changeRootViewController:#"ViewController"];
OR
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate changeRootViewController:#"MainViewController"];
I want to manage view controllers from my main controller swapping controllers in and out without Navigationbar.Please help me figure out the best possible approach and avoid leaks as well.
Look at this piece of code:
if (controllerName == #"ViewController") {
ViewController *lviewController =[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
}
When you alloc "lviewController", its retain count is 1;
when you do "self.viewController" as I suppose viewController is a retained property, then lviewController retain count is increased to 2;
then you release it, balancing the previous alloc, and retain count returns to 1;
finally you assign it to rootViewController, which is a retained property, so again lviewController retain count is 2;
finally when you "swap" view controller in your window, the lviewController is released, so it retain count becomes 1. As you can see, it will never be dealloc'd. This means that each time you call this function, you make a leak.
You require to change some of your statement in your code ..
This line have no meaning ..
imgView = UIViewContentModeScaleToFill;
There is a function by using that you have to set the value of the UIImageView property to UIViewContentModeScaleToFill find that in a UIImageView documentation.
[imageView setContentMode:UIViewContentModeScaleToFill];
The same with this...
lviewController.view = nil; //Remove this from your code ..
And finally change the implmentation for the dealloc function and remember [super dealloc]; should be in the last in any implementation of dealloc .
- (void)dealloc {
[imgView release];
imgView = nil;
[super dealloc];
}
The probable leak is due to the code inside "SecondViewController", "MainViewController", "ViewController" classes. And the reason for crash is you are releasing image view after [super dealloc]
try this,
- (void)dealloc {
[imgView release];
imgView = nil;
[super dealloc];
}
I have a number of tabs in my app. The tabs are working with no issues, but I'm getting some warning messages (in the title above) which I would like to get rid of. My code is as follows:
-(void)pressItem1:(id)sender {
[self presentModalViewController:settingsViewController animated:YES];
}
-(void)pressItem2:(id)sender {
[self presentModalViewController:infoViewController animated:YES];
}
-(void)pressItem3:(id)sender {
[self presentModalViewController:aboutViewController animated:YES];
}
-(void)viewDidLoad {
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"background.png"]];
CGRect frame = CGRectMake(0, 0, 480, 49);
UIView *v = [[UIView alloc] initWithFrame:frame];
UIImage *i = [UIImage imageNamed:#"smallMenuBackground.png"];
UIColor *c = [[UIColor alloc] initWithPatternImage:i];
v.backgroundColor = c;
[c release];
[mainTabBar insertSubview:v atIndex:0];
[v release];
[settingsBarItem setAction:#selector(pressItem1:)];
[infoBarItem setAction:#selector(pressItem2:)];
[aboutBarItem setAction:#selector(pressItem3:)];
//initialSyncSwitch = NO;
[super viewDidLoad];
}
The tabs are working, but there is probably a better way of doing it so I don't get these warnings.
Regards,
Stephen
You don't set actions directly on a UITabBarItem. Instead, you should be implementing the UITabBarDelegate in the UIViewController that creates it. Specifically, the delegate should implement:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
In here, you can call pressItem1, pressItem2, etc based on which item is passed.
-(IBAction)startClick:(id)sender{
stick.highlighted = YES;
}
-(void)viewDidLoad{
[super viewDidLoad];
stick = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"ball1.png"]];
stick.userInteractionEnabled= YES;
stick.highlightedImage = [UIImage imagedNamed:#"ball2.png"];
[self.view addSubview:stick];
}
Button does not work after i type viewDidLoad method. Pls help. Thx. stick is linked to a uiimageview.
Hello as you said stick is linked to UIImageView , then it is a bit ambiguous. It's not clear whether you have declared an IBOutlet for this and connected to an UIImageview in xib or you have declared it as a variable in header file . There are two methods both of which works fine
Method 1:
Declare an IBoutlet in .h file and connect it to an Imageview in xib . Calling methods as follows
-(void)viewDidLoad{
[super viewDidLoad];
stick.image = [UIImage imageNamed:#"firstImage.png"];
stick.highlightedImage = [UIImage imageNamed:#"secondImage.png"];
}
-(IBAction)startClick:(id)sender{
stick.highlighted = YES;
}
would serve your purpose. The method is called from a button in xib on touch up inside event. In case you want to call this method from bar button all you need is to hook up selector of bar button to startclick method.
//2nd Method
If you have declared your Imageview in header as UIImageView* stick;
in viewDidLoad method you need to allocate it as
-(void)viewDidLoad{
[super viewDidLoad];
if (!stick) {
stick = [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
[stick setImage:[UIImage imageNamed:#"firstImage.png"]];
[stick setHighlightedImage:[UIImage imageNamed:#"secondImage.png"]];
}
UIBarButtonItem* barButton = [[UIBarButtonItem alloc] initWithTitle:#"Click" style:UIBarButtonItemStylePlain
target:self action:#selector(startClick:)];
self.navigationItem.rightBarButtonItem = barButton;
[barButton release];
}
-(void)startClick:(id)sender{
stick.highlighted = YES;
}
Hope it helps !!
might be due to :
-(void)viewDidLoad
{
[super viewDidLoad];
stick = [UIImageView alloc]initWithImage:[UIImage imageNamed:#"ball1.png"];
stick.userInteractionEnabled= YES;
// stick.highlightedImage = [UIImage imaged:#"ball2.png"];
stick.highlightedImage = [UIImage imageNamed:#"ball2.png"];
[self.view addSubview:stick];
}
I have a viewcontroller that repeatedly repositions 6 items within a uiscrollview. However, even though I've limited the number of items within the uiscrollview to 6, I'm still leaking memory when i update their position and their image. Can someone let me know if the following code which represents a unit within the uiscrollview is properly coded? startLoad is the method that I call after to reload the image.
#import "ScrollUnit.h"
#implementation ScrollUnit
#synthesize index;
#synthesize ProductToDisplay;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
-(void)startLoad
{
[imageview removeFromSuperview];
[imageview release];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage)
object:nil];
[queue addOperation:operation];
[operation release];
}
-(void)loadImage
{
NSString *myimageName = [self.ProductToDisplay valueForKey:IMAGEKEY];
NSString *myimageUrl = [NSString stringWithFormat:#"%#/%#",IMAGE_SERVICE,myimageName];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myimageUrl]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image
{
imageview = [[[UIImageView alloc] initWithFrame:CGRectMake(9, 0, 320, 320)]retain];
imageview.contentMode = UIViewContentModeScaleAspectFit;
imageview.backgroundColor = [UIColor whiteColor];
imageview.image = image;
[self addSubview:imageview];
[imageview release];
//[image release];
}
- (void)dealloc {
[super dealloc];
}
#end
Get rid of the retain message on this line and you should be all set:
imageview = [[[UIImageView alloc] initWithFrame:CGRectMake(9, 0, 320, 320)]retain];
The reason why you need to do this is because you already own the object by calling alloc, so at that point, the relative reference count is 2.
Once you invoke addSubview:, passing in the imageview, the reference count gets bumped to 3, then right back down to 2 once you release it on the next line.
So once that object gets sent release in -dealloc, you're still stuck because the reference count is now 1, not 0 as you expected.
There is also another little thing that might bug (or not). You don't release imageview before you assign it in displayImage method. As long as only startLoad is called you are fine but if displayImage is called from the outside then you still leak.
You might want to use a property with retain and then synthesis the getter and setter methods. This way the iOS will release your previous assignment before it retains your new assigned object. That said then you need to release created image view right were you create it and you have to use "self.imageview" in order to make sure that you use the setter (setImageview).
I'm having a memory problem related to UIImageView. After adding this view to my UIScrollView, if I try to release the UIImageView the application crashes. According to the stack trace, something is calling [UIImageView stopAnimating] after [UIImageView dealloc] is called. However, if I don't release the view the memory is never freed up, and I've confirmed that there remains an extra retain call on the view after deallocating...which causes my total allocations to climb quickly and eventually crash the app after loading the view multiple times. I'm not sure what I'm doing wrong here though...I don't know what is trying to access the UIImageView after it has been released. I've included the relevant header and implementation code below (I'm using the Three20 framework, if that has anything to do with it...also, AppScrollView is just a UIScrollView that forwards the touchesEnded event to the next responder):
Header:
#interface PhotoHiResPreviewController : TTViewController <UIScrollViewDelegate> {
NSString* imageURL;
UIImage* hiResImage;
UIImageView* imageView;
UIView* mainView;
AppScrollView* mainScrollView;
}
#property (nonatomic, retain) NSString* imageURL;
#property (nonatomic, retain) NSString* imageShortURL;
#property (nonatomic, retain) UIImage* hiResImage;
#property (nonatomic, retain) UIImageView* imageView;
- (id)initWithImageURL:(NSString*)imageTTURL;
Implementation:
#implementation PhotoHiResPreviewController
#synthesize imageURL, hiResImage, imageView;
- (id)initWithImageURL:(NSString*)imageTTURL {
if (self = [super init]) {
hiResImage = nil;
NSString *documentsDirectory = [NSString stringWithString:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
[self setImageURL:[NSString stringWithFormat:#"%#/%#.jpg", documentsDirectory, imageTTURL]];
}
return self;
}
- (void)loadView {
[super loadView];
// Initialize the scroll view
hiResImage = [UIImage imageWithContentsOfFile:self.imageURL];
CGSize photoSize = [hiResImage size];
mainScrollView = [[AppScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds];
mainScrollView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
mainScrollView.backgroundColor = [UIColor blackColor];
mainScrollView.contentSize = photoSize;
mainScrollView.contentMode = UIViewContentModeScaleAspectFit;
mainScrollView.delegate = self;
// Create the image view and add it to the scrollview.
UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, photoSize.width, photoSize.height)];
tempImageView.contentMode = UIViewContentModeCenter;
[tempImageView setImage:hiResImage];
self.imageView = tempImageView;
[tempImageView release];
[mainScrollView addSubview:imageView];
// Configure zooming.
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
CGFloat widthRatio = screenSize.width / photoSize.width;
CGFloat heightRatio = screenSize.height / photoSize.height;
CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
mainScrollView.maximumZoomScale = 3.0;
mainScrollView.minimumZoomScale = initialZoom;
mainScrollView.zoomScale = initialZoom;
mainScrollView.bouncesZoom = YES;
mainView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
mainView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
mainView.backgroundColor = [UIColor blackColor];
mainView.contentMode = UIViewContentModeScaleAspectFit;
[mainView addSubview:mainScrollView];
// Add to view
self.view = mainView;
[imageView release];
[mainScrollView release];
[mainView release];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return imageView;
}
- (void)dealloc {
mainScrollView.delegate = nil;
TT_RELEASE_SAFELY(imageURL);
TT_RELEASE_SAFELY(hiResImage);
[super dealloc];
}
I'm not sure how to get around this. If I remove the call to [imageView release] at the end of the loadView method everything works fine...but I have massive allocations that quickly climb to a breaking point. If I DO release it, however, there's that [UIImageView stopAnimating] call that crashes the application after the view is deallocated.
Thanks for any help! I've been banging my head against this one for days. :-P
Cheers,
Josiah
Move the release of imageView before the point where you set it. This way you release the object before changing where the imageView pointer points to:
// Create the image view and add it to the scrollview.
UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, photoSize.width, photoSize.height)];
tempImageView.contentMode = UIViewContentModeCenter;
[tempImageView setImage:hiResImage];
// release old object
[imageView release];
// set the pointer to point at a new object
self.imageView = tempImageView;
[tempImageView release];
[mainScrollView addSubview:imageView];
Then at the bottom of your method where you release the other objects, remove the line:
[imageView release];
Ideally, class level variables should be released in the class' dealloc() method
Looks like imgView is a class level variable and you are releasing that at the end of the method call.
If you have a variable that you would like to release at the end of the method -- it should be a method-level variable. So, in your case, try making the imgView a method level variable. Then you should be able to release it at the end of the method without any problem
Why do you create a temporary view? Do you call loadView more than once?
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, photoSize.width, photoSize.height)];
[self.imageView setContentMode:UIViewContentModeCenter];
[self.imageView setImage:hiResImage];
[mainScrollView addSubview:self.imageView];
[self.imageView release]
Or release it in dealloc since it's an instance variable? addSubview retains your UIImageView, so it would be weird if it crashed because the object isn't present. Have you tried setting out breakpoints?