in my Mac iPhone simulator (iPhone simulator 4.0) i run my app without problem, but when i change it to another Mac which runs iPhone simulator 4.2 it crushes on a button click somewhere in the app, could the version of the debugger (4.0 and 4.2) be the cause of a potential crash ? thx in advance :))
EDIT
this is the code i have doubt it may cause crash 'cause i use in it a UIPickerView code :
- (void)viewDidLoad {
((UILabel *)[[[[[[switchCommerce subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:0]).text = #"oui";
((UILabel *)[[[[[[switchCommerce subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:1]).text = #"non";
((UILabel *)[[[[[[switchStationDeLavage subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:0]).text = #"oui";
((UILabel *)[[[[[[switchStationDeLavage subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:1]).text = #"non";
[rayonDeRechercheSlider setValue:35 animated:YES];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
CGAffineTransform transform=CGAffineTransformMakeTranslation(0,480);
pickerViewTypeCarburant.transform=transform;
pickerViewNomStation.transform=transform;
[UIView commitAnimations];
[super viewDidLoad];
typeCarburantTextField.delegate=self;
nomDeStationTextField.delegate=self;
pickerArrayTypeCarburant=[[NSMutableArray alloc] initWithObjects:#"Sans Plomb 95",#"Gazole",#"Super Gazole",#"GNV",#"Sans Plomb 98",#"SP95-E10",#"E85",nil];
pickerArrayNomStation=[[NSMutableArray alloc] initWithObjects:#"TOTAL",#"SHELL",#"ESSO",#"CARREFOUR",#"BP",#"AGIP",#"CASINO",#"LECLERC",#"AUCHAN",#"ELF",#"AVIA",#"SUPER U",nil];//added
}
One potential problem in your code is that you appear to be assigning to your mutable array properties (pickerArrayTypeCarburant & pickerArrayNomStation) without using the self. notation. What this means is that the arrays are being assigned without using retain semantics (presuming that your #property declaration for the arrays is told to use retain).
The effect of this is that when you try to access this array later in your code you will find that the array has not been retained, and you will likely be receiving some kind of memory warning. Try this instead:
self.pickerArrayTypeCarburant=[[NSMutableArray alloc] initWithObjects:#"Sans Plomb 95",#"Gazole",#"Super Gazole",#"GNV",#"Sans Plomb 98",#"SP95-E10",#"E85",nil];
self.pickerArrayNomStation=[[NSMutableArray alloc] initWithObjects:#"TOTAL",#"SHELL",#"ESSO",#"CARREFOUR",#"BP",#"AGIP",#"CASINO",#"LECLERC",#"AUCHAN",#"ELF",#"AVIA",#"SUPER U",nil];
It's hard to tell if that will solve your problem since I don't know what error is being thrown, however if it is memory related then that could be the culprit.
To be sure, you could run your app in Instruments and see if there are any leaks or allocations where there shouldn't be.
EDIT:
In response to your comment regarding properties, your header file should probably declare your NSMutableArrays like this:
YourClass.h
#interface YourClass {
NSMutableArray *pickerArrayTypeCarburant;
NSMutableArray *pickerArrayNomStation;
}
#property (nonatomic, retain) NSMutableArray *pickerArrayTypeCarburant;
#property (nonatomic, retain) NSMutableArray *pickerArrayNomStation;
// Any method names here...
#end
And at the top of your .m file, just underneath the #implementation line:
#synthesize pickerArrayTypeCarburant, pickerArrayNomStation;
The #synthesize part will automatically create the required accessors and mutators for your properties, based on the information you provide on the lines with #property. In this case, I have defined that the properties should use retain semantics, which means that when you assign a value to your property using self. (i.e. self.pickerArrayNomStation = anArray;) the array you assign to it will automatically be retained by your property. Make sure you include the self. when assigning to a property that uses retain, as this is what tells it to use the generated mutator method, rather than just assigning to the instance variable without retaining.
By the way, make sure that when you generate retained properties in this way that you call [myProperty release]; in the dealloc method, and (assuming your class is a view controller...) self.myProperty = nil in your viewDidUnload method. This ensures that any retained objects are released properly when your views and view controllers are no longer needed.
If you need further information about this stuff, Apple's documentation is your friend. I found their programming guides really helpful when I was starting out. The guide I linked you in my comment under your answer is a good one to start with.
Hope this helps.
EDIT 2
Not sure if this will help, but I have sometimes found that assigning arrays in this way is a little safer... at the bottom of the ViewDidLoad method where you are assigning to your array property, change the code to this:
NSMutableArray *newArrayTypeCarburant = [[NSMutableArray alloc] initWithObjects:#"Sans Plomb 95",#"Gazole",#"Super Gazole",#"GNV",#"Sans Plomb 98",#"SP95-E10",#"E85",nil];
NSMutableArray *newArrayNomStation = [[NSMutableArray alloc] initWithObjects:#"TOTAL",#"SHELL",#"ESSO",#"CARREFOUR",#"BP",#"AGIP",#"CASINO",#"LECLERC",#"AUCHAN",#"ELF",#"AVIA",#"SUPER U",nil];
self.pickerArrayTypeCarburant = newArrayTypeCarburant;
self.pickerArrayNomStation = newArrayNomStation;
[newArrayTypeCarburant release];
[newArrayNomStation release];
Related
Being new to objective-C coding I started out writing a basic app, fully programmatically (not using storyboards or xib) in one file, my AppViewController h and m files.
Everything worked lovely.
So then I wanted to break up the mass of code by subclassing sections, and everything went well apart from the UIPickerView. In fact simply commenting out the [background addSubview:colorPicker]; seemed to totally fix the issue. I never found the answer online so I proceeded to make a new document to replicate said issue.
So here goes:
UIPickerViewController.h
#import <UIKit/UIKit.h>
#import "Picker.h"
#interface UIPickerViewController : UIViewController
#end
Simply imports my new class.
UIPickerViewController.m
#import "UIPickerViewController.h"
#interface UIPickerViewController ()
#end
#implementation UIPickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *superview = self.view;
int height = superview.bounds.size.height;
int width = superview.bounds.size.width;
CGRect popupRect = CGRectMake(0, 0, width, height);
UIView *popup = [[UIView alloc]initWithFrame:popupRect];
popup.tag = 8;
[superview addSubview:popup];
Picker *picker = [[Picker alloc]initWithFrame:popupRect];
[picker viewAddTypeScreenToView:superview];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Sets up a new view with a tag (so that i could reference it later with my new class)
Then actions a method from my new class to populate my new view.
Picker.h
#import <UIKit/UIKit.h>
#interface Picker : UIView
<UIPickerViewDataSource,UIPickerViewDelegate>
{
UIPickerView *colorPicker;
NSMutableArray *colorsArray;
}
#property (nonatomic, retain) UIPickerView *colorPicker;
#property (nonatomic, retain) NSMutableArray *colorsArray;
#property (strong,nonatomic) UILabel *myValue;
-(void)viewAddTypeScreenToView:(UIView*)superview;
#end
Setting up my variables and accessible method.
Picker.m
#import "Picker.h"
#implementation Picker
#synthesize colorsArray;
#synthesize colorPicker;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(void)viewAddTypeScreenToView:(UIView*)superview
{
UIView *baseView =[superview viewWithTag:8];
int height = baseView.bounds.size.height;
int width = baseView.bounds.size.width;
CGRect fullScreen = CGRectMake(0, 0, width, height);
UIView *background = [[UIView alloc]initWithFrame:fullScreen];
background.backgroundColor = [UIColor blackColor];
colorsArray = [[NSMutableArray alloc] initWithObjects:#"Red",#"Blue",#"Yellow",#"Green",nil];
CGRect myPickerRect = CGRectMake(10, 70, (width/2)-40, 200);
colorPicker = [[UIPickerView alloc]initWithFrame:myPickerRect];
colorPicker.dataSource = self;
colorPicker.delegate = self;
colorPicker.showsSelectionIndicator = YES;
[colorPicker selectRow:2 inComponent:0 animated:YES];
CGRect labelFrame = CGRectMake(10, 10, 180, 50);
_myValue = [[UILabel alloc]initWithFrame:labelFrame];
_myValue.textColor = [UIColor redColor];
_myValue.text = #"select colour";
[background addSubview:_myValue];
[background addSubview:colorPicker];
[baseView addSubview:background];
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return colorsArray.count;;
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return colorsArray[row];
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
_myValue.text = [NSString stringWithString:colorsArray[row]];
}
#end
And finally the initiation called by the method in the picker class file.
This gives me an error along these lines
-[UITableViewCellContentView pickerView:titleForRow:forComponent:]: unrecognized selector sent to instance 0x8f2b000
2014-03-19 10:29:48.407 Briefcase[1800:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCellContentView pickerView:titleForRow:forComponent:]: unrecognized selector sent to instance 0x8f2b000'
Which i've read is to do with either the datasource, or ARC systems, however none of the responses that I have found relate to or work with the type of set up that I have above. I'm sure it's something really simple but after a few days of failed searching, it's officially driving me crazy.
The problem is most likely that the instance of Picker that is being created in UIPickerViewController is never added to the view hierarchy and thus gets released prematurely (provided we're talking about a project using ARC here).
This leads to the pickerview's delegate and datasource becoming invalid and, basically, pointing at any random object. That's what is causing your crash: A message to your delegate cannot be delivered because the delegate is dead already. The picker still keeps a pointer which used to point at the delegate, but which has become invalid and points at a random object now, in this case a table view cell, which basically doesn't know what to do with this message and crashes.
The problem should go away if you add Picker *picker as an ivar or a retaining / strong property to UIPickerViewController.h - this will retain the picker beyond the scope of the viewDidLoad method and should keep it alive.
But that would be just a workaround, the real problem is your overall design. You said you're new to objective-c and indeed, it looks like you lack a basic understanding of iOS view and view controller hierarchies and, to some degree, the concept of object oriented programming. You might want to dig into something more basic before trying to fix your code because, quite frankly, it should be rather re-written than fixed.
I'd be happy to provide you with suggestions about how to structure your code, but please provide some information about what functionality you'd like to achieve first.
Edit (in response to your comment):
As a rule of thumb, do not spread functionality over several classes unless necessary. For objects, which serve a rather infrastructural purpose, like a specialized textfield or a pickerview, always ask yourself: "If I would like to reuse that object in another project, would that be as easy as using any other existing object, like, for example, UILabel?" If the answer is "No", then something is wrong. Ideally, interface objects are self-contained and to use them, you just invoke them, add them to a view and tell them, which text to display or which options to offer. If that information is subject to change or if the object needs to interact with other parts of your code, make use of delegation and protocols. Under no circumstances should the functionality of your object be tied to hard coded values or rely to some view to have a certain tag.
If you subclass UIView, the resulting object should behave like any other instance of UIView. It should be added to the view hierarchy by you or some object, but it shouldn't add or remove itself. If it works without being added to the view hierarchy at all, something is wrong. A view serves the purpose of being a part in your interface and all the logic it contains should work to that end, not more, not less.
Normally, interface objects should not interfere with one another. If something happens to one object (button pressed, option selected, text changed...) and another object is supposed to reflect that change, it is the view controllers responsibility to make that happen. The view controller is the place where the logic happens. If there is a task which requires a lot of complex logic, it might be a good idea to encapsule that logic into a purpose build class. One such example would be a class which manages network connections. This class should be again self contained: If the view controller needs some remote information, it asks your network class. Once your network class has that information (or failed to retrieve it), it reports back to your view controller. The view controller then updates the interface - under no circumstance should the networking class contain code which affects the interface.
It is important to understand that you could very well ignore these rules and still end up with a working app. And in some cases, the "direct" way may appear to be easier to implement and thus may look very tempting. But you'll pay the price later - once you start debugging your code. If your picker does not behave the way it should, you need to look into several places and wrap your mind around several objects, just to make one interface object behave right. And likely you will break one functionality while fixing the other.
So, try to make it right from the start, even though it requires more planning and learning. Trust me, it pays out, I started out just like you several years ago ;)
i am using ARC, my code is as :
-(void)viewAllCustomer:(id)sender
{
if([self.popOver isPopoverVisible])
{
[self.popOver dismissPopoverAnimated:YES];
}
CustomersViewController *allCustomer=[[CustomersViewController alloc]init];
[allCustomer setDelegateAction:self];
[allCustomer.view setFrame:CGRectMake(0, 0, 370, 420)];
UINavigationController *navController=[[UINavigationController alloc]initWithRootViewController:allCustomer];
UIPopoverController *_popOver=[[UIPopoverController alloc]initWithContentViewController:navController];
[_popOver setPassthroughViews:[NSArray arrayWithObject:self]];
[_popOver setPopoverContentSize:CGSizeMake(370, 420)];
UIButton *button=(UIButton *)sender;
// 60.0, 54.0
CGRect buttonFrame=CGRectMake(button.frame.origin.x+25, button.frame.origin.y+35, 10,10);
[_popOver presentPopoverFromRect:buttonFrame inView:self permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
self.popOver=_popOver;//popOver is (nonatomic,retain)
}
i am getting memory leak as:
Thanks.
i my self have to give answer of this question, thanks to #abizern.Actually the leak was due to _var._var is just a different name for the instance variable (presumably so you don't accidentally access directly it when you meant to use an accessor).In the code provided to me was accidentally assigning _var to self.var.
i simply made the #property(nonatomic, retain) and use it as self.var in implementation file.No more memory leaks .Also in arc property are auto synthesise, so no more need to explicitly #synthesise removed.
while going through developer apple i found this:
In this example, it’s clear that myString is a local variable and _someString is an instance variable.
In general, you should use accessor methods or dot syntax for property access even if you’re accessing an object’s properties from within its own implementation, in which case you should use self:
- (void)someMethod {
NSString *myString = #"An interesting string";//my bad was that i have taken _myString
self.someString = myString;//again self.someString = _myString //wrong
// or[self setSomeString:myString];
}
I have a small problem with ARC and dealloc of the BaseViewController class being called after the instantiation inside the loop and I don't know why. What I'm trying to do is basically store all the base view controllers on an array.
#interface CategoriesContainerViewController ()
#property (nonatomic, strong) IBOutlet UIScrollView* scrollView;
#property (nonatomic, strong) NSMutableArray* categoriesViews;
#end
- (void)viewDidLoad {
[super viewDidLoad];
// Get the categories from a plist
NSString* path = [[NSBundle mainBundle] pathForResource:#"categories" ofType:#"plist"];
NSDictionary* dict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSMutableArray* categories = [dict objectForKey:#"Categories"];
NSLog(#"%i", [categories count]);
// Setup the scrollview
_scrollView.delegate = self;
_scrollView.directionalLockEnabled = YES;
_scrollView.alwaysBounceVertical = YES;
_scrollView.scrollEnabled = YES;
CGRect screenRect = [[UIScreen mainScreen] bounds];
// Loop through the categories and create a BaseViewController for each one and
// store it in an array
for (int i = 0; i < [categories count]; i++) {
BaseViewController* categoryView = [[BaseViewController alloc]
initWithCategory:[categories objectAtIndex:i]];
CGRect frame = categoryView.view.frame;
frame.origin.y = screenRect.size.height * i;
categoryView.view.frame = frame;
[_scrollView addSubview:categoryView.view];
[_categoriesViews addObject:categoryView];
}
}
You are committing a common beginner mistake by keeping a reference to a view controller's view, but not the view controller itself.
You create a BaseViewController object in a local variable categoryView. That's a strong reference, so the object is kept around. Then the loop repeats, and you create a new BaseViewController, replacing the old value in categoryView. When you do that, there are no longer any strong references to the previous BaseViewController that was in categoryView, so it gets deallocated.
If you want the BaseViewController to stick around, you need to keep a strong reference to it somewhere.
In addition to that, you are breaking another rule of iOS development. You should never put one view controller's view(s) inside another view controller's unless you use the parent/child view controller support that was added in iOS 5 and extended in iOS 6. The docs say do NOT do that.
Mixing views from multiple view controllers on the screen will cause you no end of problems. There is tons of housekeeping you have to do in order to make it work, and not all of that housekeeping is documented. Its possible, but it will take you many weeks to iron out the bugs, if you ever able to. Plus, since you are doing something that Apple expressly says not to do, the burden is on you to make it work correctly, and there is a substantial risk that a new iOS release will break your app.
Initialize BaseViewController above for loop and then store the array value inside the object of BaseViewController. Because every time it is allocating and initializing. So setting the previous object to nil. Hence the issue causes to be deallocated.
I have a question. There may be a very simple solution to this question but I am not able to figure it out yet. If I use a property say #property(nonatomic, retain)UIView *mainView.
Now I synthesize it in .m file and release it in the dealloc method as following:
- (void)dealloc {
[mainView release], mainView = nil;
[super dealloc];
}
Then in my viewDidLoad, I'm allocating it and adding it as the subview of my self.view like following:
- (void) viewDidLoad {
mainView = [[UIView alloc] init];
.
.
.
[self.view addSubView: mainView];
}
Now I understand that at this point my mainView would have 3 reference counts (one from alloc, one because it's a retained property, and the third one when I added it to self.view), its parent controller would own it too.
Now, my question is if after adding my view to self.view, I release my mainView using
[mainView release];
My app crashes when I go back to the previous view as I am sending release to already deallocated object. Now my question is how am I overreleasing my view here. what am I missing because when I use following code it works fine and no crashes occur.
- (void) viewDidLoad {
UIView *newView = [[UIView alloc] init];
self.mainView = newView;
[newView release];
.
.
.
[self.view addSubView: mainView];
}
I know why this second viewDidLoad method works but what I dont know is why first one fails, I am supposed to release my view after adding it to self.view. Right?
NOTE: I understand that in the first viewDidLoad, I can use autorelease method to release the view that is being assigned to the ivar and it wont crash but the whole point is I am trying to reduce the use of autorelease as much as possible. And I am not using ARC at all
I would really appreciate the explanation and suggestions.
From your question:
Now i understand that at this point my mainView would have 3 reference
counts (one from alloc, one coz its a retained property and the third
one when i added it to self.view)
You didn't assign through the property but assigned directly to the instance variable, so there was no retain; only in ARC does assigning to the instance variable retain the value. So, do not perform the manual release.
In order for your #property to retain the mainView, you should use it as self.mainView and not just mainView. If you use the latter alone, it will not retain it. Basically if you call self.mainView = ... it is calling a setter method for mainView which does a [mainView retain]; internally. When you are directly assigning it, it wont execute this setter and retain will not be executed.
You should try it like this,
self.mainView = [[[UIView alloc] init] autorelease];
[self.view addSubView:self.mainView];
or as shown in your question.
UIView *newView = [UIView alloc] init];
self.mainView = newView;
[newView release];
[self.view addSubView:self.mainView];
You can also try using ARC for your project. Your code will look like this in ARC,
self.mainView = [[UIView alloc] init];
[self.view addSubView:self.mainView];
Check the documentation for more details.
In your first viewDidLoad method you are not referring to self.mainView only mainView thats why its not retained, in order to retain property work you have to set mainView using self.mainView!
I am new to iPhone programming and Objective-C.
I am building a View-based application.
The problem is that none of the UIViewController's dealloc functions are ever called.
I have decided to unload all my retained objects programmaticaly, right before presenting the next UIViewController class.
I have resolved all the leaks detected by Xcode, tested the application with Leaks and Allocations Tools and everything seams OK, but the memory used builds up to around 180 MB and the app crashes.
The self.retainCount before presenting the next UIViewController is 1, the objects owned are released and the pointers are nil, but still the memory builds up.
Can you give me a clue? If needed I will post some code samples. Or can you send me some references to something like Objective-C memory management 101?
This is my interface:
#interface GameScreen : UIViewController
{
IBOutlet UILabel *timeLabel;
IBOutlet UIView *gameView;
IBOutlet UIImageView *gameViewFrame;
IBOutlet UIButton *showOutlineButton;
UIImage *puzzleImage;
UIView *optionsView;
UIView *blockView;
NSTimer *timer;
UIImageView *viewOriginalPicture;
SHKActivityIndicator *activityIndicator;
BOOL originalPictureShown;
BOOL outLineShown;
}
#property (nonatomic, retain) IBOutlet UILabel *timeLabel;
#property (nonatomic, retain) IBOutlet UIView *gameView;
#property (nonatomic, retain) IBOutlet UIImageView *gameViewFrame;
#property (nonatomic, retain) IBOutlet UIButton *showOutlineButton;
#property (nonatomic, retain) UIImage *puzzleImage;
And here is the implementation:
- (id) initWithPuzzleImage: (UIImage *) img
{
if((self = [super init]))
{
puzzleImage = [[UIImage alloc] init];
puzzleImage = img;
}
return self;
}
This is the function called when the user taps the exit button:
- (void) onExit
{
[timer invalidate];
CurrentMinuts = 0;
CurrentSeconds = 0;
//remove piece configurations
[pieceConfigMatrix removeAllObjects];
[pieceFramesMatrix removeAllObjects];
PuzzleViewController *modalView = [[PuzzleViewController alloc] init];
[self unloadObjects];
[self presentModalViewController:modalView animated:YES];
[modalView release];
}
And the unloadObjects function:
- (void) unloadObjects
{
[self resignFirstResponder];
[viewOriginalPicture release];
viewOriginalPicture = nil;
[timeLabel release];
timeLabel = nil;
[gameView release];
gameView = nil;
[originalImage release];
originalImage = nil;
[gameViewFrame release];
gameViewFrame = nil;
[timer release];
[showOutlineButton release];
showOutlineButton = nil;
}
I have a lead of what I do wrong, but I am not sure. Let me explain. I am adding the puzzle pieces to the 'gameView' property. For this, I have a 'SplitImage' object. The following function is called in - (void) viewDidLoad:
- (void) generatePuzzleWithImage:(UIImage *) image
{
SplitImage *splitSystem = [[SplitImage alloc] initWithImage:image andPuzzleSize:gPuzzleSize];
[splitSystem splitImageAndAddToView:self.gameView];
[splitSystem release];
}
Next, initialization function for the SplitImage class and the splitImageAndAddToView function:
- (id) initWithImage: (UIImage *) image andPuzzleSize: (int) pSize
{
if((self = [super init]))
{
UIImage *aux = [[[UIImage alloc] init] autorelease];
pieceCenterSize = [SplitImage puzzlePieceSizeForNumberOfPieces:pSize];
UIImage *outSideBallSample = [UIImage imageNamed:#"sampleHorizontal.jpg"]; //convexity size for puzzle size
outSideBallSample = [outSideBallSample resizedImageWithContentMode:UIViewContentModeScaleAspectFit bounds:CGSizeMake(pieceCenterSize, pieceCenterSize) interpolationQuality:kCGInterpolationHigh];
outSideBallSize = roundf(outSideBallSample.size.height);
puzzleSize = pieceCenterSize * pSize;
pieceNumber = pSize;
if(image.size.height < puzzleSize || image.size.height > puzzleSize || image.size.width < puzzleSize || image.size.width > puzzleSize)
{
aux = [SplitImage resizeImageForPuzzle:image withSize:puzzleSize];
aux = [SplitImage cropImageForPuzzle:aux withSize:puzzleSize];
}
aux = [aux imageWithAlpha];
originalImage = [[UIImage imageWithCGImage:aux.CGImage] retain];
mainImage = aux.CGImage;
imageSize = CGSizeMake(aux.size.width, aux.size.height);
NSLog(#"%#", NSStringFromCGSize(imageSize));
splitImageSize = CGSizeMake(pieceCenterSize + 2*outSideBallSize, pieceCenterSize+2*outSideBallSize);
}
return self;
}
- (void) splitImageAndAddToView: (UIView *) view
{
for (int i = 0; i < pieceNumber; i++)
for(int j = 0; j < pieceNumber; j++)
//some code
UIImage *mask;
mask = [self randomlyRetriveMaskWithPrefix:1 forPieceAtI:i andJ:j];
CGImageRef split = CGImageCreateWithImageInRect(mainImage, cuttingRect);
PuzzlePiece *splitView = [[PuzzlePiece alloc] initWithImage:[UIImage imageWithCGImage:split] andMask:mask centerSize:pieceCenterSize objectMatrixPosition:i*pieceNumber+j outSideBallSize:outSideBallSize pieceType:pieceType pieceFrame:cuttingRect];
[pieceFramesMatrix addObject:[NSValue valueWithCGRect:cuttingRect]];
[splitView setTag:(i+1)*100+j];
[view addSubview:splitView];
CGImageRelease(split);
[splitView release];
}
Thank you,
Andrei
Objective-C memory management 101 is here:
https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
Ignore the stuff on garbage collection, it isn't available for iOS.
It's not normal to release objects before presenting the next UIViewController.
Assuming you have a NIB, its contents will be loaded the first time that you (or the system) accesses the view member. Your view controller will get a call to loadView, then subsequently to viewDidLoad. If you have any views you want to add programmatically, you can do that in loadView or viewDidLoad, if you want to interrogate objects loaded from the NIB then you can do that in viewDidLoad.
Once loaded, the view will remain in memory unless and until a low memory warning occurs. At that point it'll be released. You'll get viewDidUnload. You should release anything view related that you've still got an owning reference to in there, and set to nil any weak references you may have.
Any attempt to access the view property subsequently will cause the NIB to be reloaded, etc.
So, when presenting a new UIViewController, just present it. If you create objects that are used only for display of that controller then do so on viewDidLoad, and release them on viewDidUnload.
That all being said, the Leaks tool in Instruments should be able to tell you which types of object are leaking and where you first allocated them, so it makes finding leaks really quite easy. The only thing to watch out for is that if one object handles its properties/members entirely correctly but is itself leaked then anything it creates will generally also leak. So when something leaks, check the thing that created it isn't also leaking before tearing your hair out over why you can't find a problem.
First, retainCount is useless.
Activity Monitor is pretty close to just as useless. As well, the behavior in the simulator can be quite different on the memory use front. Better to focus debugging of a problem like this on the device.
Next, this:
The problem is that none of the
UIViewController's dealloc functions
are ever called. I have decided to
unload all my retained objects
programmaticaly, right before
presenting the next UIViewController
class.
Any time you find yourself programmatically working around incorrect behavior, you are just creating more bugs.
Step back from your custom hack and figure out why the dealloc isn't being called. Something somewhere is over-retaining the object. The allocations instrument with retain tracking turned on will show you exactly where all retains and releases are sent to the errant objects.
Leaks likely won't show anything if whatever is retaining the objects is still reachable from a global or the stack (i.e. leaks are objects that can never be used by your program again -- but there are many more ways to explode memory use without it being truly a leak).
You should also "Build and Analyze", then fix any problems it identifies.
Next, if you are seeing memory accretion of repeated operations on the user's part, then Heapshot analysis is extremely effective at figure out exactly what has gone wrong.
Some specific comments:
puzzleImage = [[UIImage alloc] init];
puzzleImage = img;
2 bugs; you are leaking a UIImage and not retaining img. That your app doesn't crash in light of the above code indicates that there is likely an over-retain elsewhere.
retainCount is not a reliable debugging tool.
You should never pay attention to or rely on retainCount. Just because you released it does not mean that some part of the program does not still have a reference to it. retainCount has no value.
Generally as a rule of thumb. If you use 'alloc' you must 'release' at some point.
Unless ofcourse you have put it into an autorelease pool.
Leaks should be able to point you to the objects that are leaking, using that, narrow down to where those objects are added, stored etc.
Post examples of your code on how you instantiate objects and where you release them, you maybe doing something wrong early on.
edit: apologies, i put 'init' not 'alloc' previously, thank you dreamlax, early morning mistake.