I am adding NSDate as a pointer with a property, and every time I unload my view, it crashes with EXC_BAD_ACCESS. I am doing (not posting full code):
.h
NSDate *scheduledDate;
#property (nonatomic, retain) NSDate *scheduledDate;
.m
#synthesize scheduledDate;
- (void)dealloc {
[super dealloc];
[asset release];
[passedDate release];
[eventDate release];
[eventName release];
}
I have not done anything else with the pointer, but I still get EXC_BAD_ACCESS. Why is this happening? Is there a different way to set the property for NSDate?
SORRY:
I fixed an error in my question code, it was only a copy and paste issue, not a fix to my problem, it still exists.
You're calling [super dealloc] before the release in your dealloc implementation. That means the [scheduledDate release] is release some non-free memory (which is no longer nil).
Specifically, change the order so [super dealloc] is last:
- (void)dealloc {
[asset release];
[passedDate release];
[eventDate release];
[eventName release];
[super dealloc];
}
Your code looks inconsistent. The #property declaration should be for "NSDate scheduledDate", not "NSString ...".
If you are not using #property (nonatomic, retain) NSDate *scheduledDate; then there is no need to synthesize scheduledDate.
Also, how are you determining the value of scheduledDate? post the code you are using for it.
Also, post the crash log that your app produces.
Your #property (nonatomic, retain) is for "passedDate", not "scheduledDate". Since "scheduledDate" is not getting instantiated and retained by #property (nonatomic, retain), then attempting to release it is attempting to release something that hasn't been created yet (it isn't being synthesized as a property).
Related
I am using following code to create NSMutableArray. When I run the same in “Profile” mode, it is showing a memory leakage.
SampleArray.h
#interface SampleArray: NSObject {
}
#property (assign, retain) NSMutableArray *array;
#end
SampleArray.m
#import "SampleArray.h"
#implementation SampleArray
#synthesize array;
-(void) viewDidLoad {
self.array =[ [NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
[self.array release];
}
#end
When I am using autorelease, then I can’t able to access the same in other function or method and return null value. Please help me to find the issue.
releasing this array in viewWilLDisappear is not a good idea, you should release in the dealloc function. You should worry about over-releasing this item and causing a program crash since viewWilLDisappear may get called multiple times during the lifetime of this ViewController.
Anyhow, you are double retaining the item beacuse your property has a retain on it (and make it nonatomic, not assign), add an autorelease to your alloc/init:
self.array =[[[NSMutableArray alloc] init] autorelease];
and move
[array release];
to your dealloc function. Or convert to ARC and don't worry any longer...
Try setting it to (nonatomic, retain), then autoreleasing.
It is better to handle memory de-allocation in your -dealloc() and set your array to nil to be more secure in your -viewDidUnload()
so it will be:
-(void) viewDidUnload
{
self.array = nil;
}
-(void) dealloc
{
[array release];
[super dealloc];
}
and like other people said, declare your property as (nonatomic, retain) instead of (assign, retain)
First of all I'm assuming that you are using
#property (nonatomic, retain) NSMutableArray *array;
use this
-(void) viewDidLoad {
array =[[NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
[array release];
}
I will recommend you to use dealloc instead of viewWillDisappear
-(void) dealloc {
[array release];
[super dealloc];
}
Explanation of your code
-(void) viewDidLoad {
// here you are allocating a mutable array thus retain count becomes one
// then you are assigning it to the property which is retain and thus retains it
// making the retain count 2
self.array =[ [NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
// here you are releasing it so its retain count becomes 1 from 2
// thus shows memory leak
[self.array release];
}
I just recently started learning Objective C/Cocoa and I know how important the memory management is and I believe this error I've been having is regarding to that.
I have a very very simple screen: two UITextView, one Button, one UILabel.
My header file has:
#interface PontaiViewController : UIViewController {
UITextField *loginField;
UITextField *passwordField;
UILabel *userID;
}
#property (nonatomic, retain) IBOutlet UITextField *loginField;
#property (nonatomic, retain) IBOutlet UITextField *passwordField;
#property (nonatomic, retain) IBOutlet UILabel *userID;
- (IBAction) btnLoginClicked:(id) sender;
The implementation has:
#implementation PontaiViewController
#synthesize loginField;
#synthesize passwordField;
#synthesize userID;
-(IBAction) btnLoginClicked:(id)sender {
NSString *string1 = #"username=";
NSString *string2 = [string1 stringByAppendingString:(loginField.text)];
NSString *string3 = [string2 stringByAppendingString:(#"&password=")];
NSString *post = [string3 stringByAppendingString:(passwordField.text)];
NSLog(#"The post is %#", post);
userID.text=loginField.text;
[string1 release];
[string2 release];
[string3 release];
[post release];
}
and it finishes with
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.loginField=nil;
self.passwordField=nil;
self.userID=nil;
}
- (void) dealloc {
[super dealloc];
[loginField release];
[passwordField release];
[userID release];
}
When I run this demo, and try to write something in the TextView, I get this error.
What could it be?
Regards,
Felipe
Also, your NSStrings are autoreleased, and then you're releasing them again (over releasing). Read up on memory management of convenience methods.
stringByAppendingString returns an autoreleased object, don't release string1, string2, string3 and post.
In viewDidUnload you set loginField to nil, then you try to release it in dealloc. This isn't right. You only need to release valid items that you own.
Additionally, (as pointed out in a comment) you need to put [super dealloc] at the end of the dealloc function.
As pointed out by others, you also should not release the strings you're getting from stringByAppendingString.
Here are some basic rules about how to manage memory in Objective-C under iOS:
https://developer.apple.com/library/ios/#documentation/general/conceptual/devpedia-cocoacore/MemoryManagement.html
One thing you will find is that you only release stuff you are responsible for, and you're not responsible for it unless it was created with one of these:
alloc, allocWithZone:, copy, copyWithZone:, mutableCopy, mutableCopyWithZone
You should comment out the following
//[string1 release];
//[string2 release];
//[string3 release];
//[post release];
since you are using helper methods and not explicitly allocating anything.
I want to make sure I understand the memory management correctly here. Is there any particular reason to use one of the assignCurrentDate methods over another here?
Also, all of these result in no memory leaks, correct?
in the .h we have:
NSDate *currentDate1;
NSDate *currentDate2;
NSDate *currentDate3;
NSDate *currentDate3;
//and
#property (nonatomic, retain) NSDate *currentDate1;
#property (nonatomic, retain) NSDate *currentDate2;
#property (nonatomic, retain) NSDate *currentDate3;
#property (nonatomic, retain) NSDate *currentDate4;
in the .m:
-(void) assignCurrentDate1
{
currentDate1 = [[NSDate date]retain];
//[NSDate date] is autoreleased
}
-(void) assignCurrentDate2
{
currentDate2 = [[NSDate date]copy];
}
-(void) assignCurrentDate3
{
self.currentDate3 = [NSDate date];
}
-(void) assignCurrentDate4
{
currentDate4 = [[NSDate alloc]init];
//[[NSDate alloc]init] is not autoreleased.
}
-(IBAction) printDate
{
NSLog ("%#", currentDate1);
NSLog ("%#", currentDate2);
NSLog ("%#", currentDate3);
NSLog ("%#", currentDate4);
}
- (void)dealloc
{
[currentDate1 release];
[currentDate2 release];
[currentDate3 release];
[currentDate4 release];
[super dealloc];
}
The rule of thumb when it comes to iOS memory management is:
For every alloc, retain, copy, or new, you must have a corresponding release or autorelease.
You are leaking in several places actually. In your header, you retain your date objects and then in your dealloc method you release them. That is correct. However, In your assignDate methods, you fail to release the copy or retained date. While [NSDate date] is autoreleased, you are retaining and copying them yourself.
There is no reason to use your assignCurrentDate methods. You can just do something like the following in your init method:
self.currentDate1 = [NSDate date];
That's it.
Edit: (Okay, that's not it.)
As Jim points out in the comments:
The retain in the header signifies that the synthesized setter for those properties will retain objects assigned to them. But if you look at the assign* methods, you'll see that only assignCurrentDate3 actually uses the property. The rest assign directly to the ivar, bypassing the synthesized setter, so they aren't retained upon assignment.
Yes, you understand memory management correctly. None of those leak, assuming you don't call the methods more than once. The second is less efficient in terms of memory use as two instances of NSDate are created. In fact, they all slightly vary performance-wise, but not in a significant way unless you are putting them into tight loops.
In terms of program design, you wouldn't want to write code like this because if you ever call 1, 2 or 4 more than once, the originally allocated instance will leak. If you're sure that this isn't a problem (e.g. if you assign in viewDidLoad and release in viewDidUnload), then you are safe using any of those styles, but if you aren't sure that this is the case, you either need to guard your assignment by releasing before assigning, or you should use the third property-based method, which does this for you.
My problem is this: I can't seem to access the variable todaysDate from the numberForPlot or numberOfRecordsForPlot functions (see below for numberForPlot), but I can from anywhere else in the file.
The NSLog in the viewDidLoad works perfectly, the date is set correctly. If I access the variable from my own class functions, then that's fine too and it works. However, when I try to access it from numberForPlot I get an error:
Program received signal: “EXC_BAD_ACCESS”.
In my header file, I have the following - note my class implements CPPlotDataSource.
#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"
#interface ResultsGraphViewController : UIViewController <CPPlotDataSource> {
NSManagedObjectContext *managedObjectContext;
CPXYGraph *graph;
NSMutableArray *eventsArray;
NSDate *todaysDate;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSDate *todaysDate;
- (void)getEvents;
- (void)configureGraph;
#end
In the implementation file, I have (relevant highlights only):
#synthesize managedObjectContext;
#synthesize eventsArray;
#synthesize todaysDate;
and
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:#"Results"];
todaysDate = [NSDate date];
NSLog(#"Set today's date to %#", todaysDate);
[self getEvents];
[self configureGraph];
}
and
-(NSNumber *)numberForPlot:(CPPlot *)plot
field:(NSUInteger)fieldEnum
recordIndex:(NSUInteger)index
{
NSLog(#"%d events in the array.", [eventsArray count]);
NSLog(#"today's date is %#.", todaysDate);
...
}
(in the last two lines, above, the number of events in the array is output successfully, but the last line causes the error).
Any ideas as to why this is a problem, and how I can get around it? I imagine it's something to do with being the CPPlotDataSource - how does this affect scoping?
Or do I just have an error in my code? All help much appreciated!
The problem is that [NSDate date] returns an autoreleased object, which you don't hold on to. It will hang around until the end of the current cycle of the run loop (why it doesn't crash immediately in your first NSLog() statement), then it will be released. When you try to access it in -numberForPlot:, it has been released and your application crashes.
To fix this, change the line in -viewDidLoad to read
self.todaysDate = [NSDate date];
You defined todaysDate to be a property with the retain attribute, so this will retain your date. Just remember to add a [todaysDate release] in your -dealloc method to prevent a leak.
I'm writing an iPhone app. I have a header file that looks like this:
#interface EditTagsViewController : UITableViewController {
NSMutableArray *allTags;
NSMutableArray *selectedTags;
NSInteger currentFavorite;
}
#property (nonatomic, retain) NSMutableArray *allTags;
#property (nonatomic, retain) NSMutableArray *selectedTags;
#property (nonatomic) NSInteger currentFavorite;
#end
In the implementation file, my viewDidLoad method looks like this:
- (void)viewDidLoad {
NSMutableArray *aTags = [[NSMutableArray alloc] initWithArray:[Tag findAllTags]];
self.allTags = aTags;
[aTags release];
NSMutableArray *sTags = [[NSMutableArray alloc] initWithArray:[Tag findByFavoriteId:currentFavorite]];
self.selectedTags = sTags;
[sTags release];
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewTag:)];
self.navigationItem.rightBarButtonItem = add;
[add release];
[super viewDidLoad];
}
Here is my dealloc method:
- (void)dealloc {
[allTags release];
[selectedTags release];
[super dealloc];
}
What's confusing to me is that when I run the app both in the simulator and on the device itself, using Instruments (memory leaks), it tells me that this line in my viewDidLoad method is leaking an array:
self.selectedTags = sTags;
It's confusing because I'm using the exact same technique with 2 different variables, and yet no leak is reported with the first one.
I feel like I'm missing something obvious here. Any ideas?
Your code looks correct to me. Is it possible that one of [Tag findAllTags] or [Tag findByFavoriteId:] is leaking? Are you making sure to set self.allTags and self.selectedTags to nil in dealloc?
Be mindful of the difference between saying self.allTags = ... and allTags = .... Because allTags is a property and has the retain attribute, whenever you assign via self.allTags = ..., it implicitly calls the setter method [self setAllTags:...], which invokes retain on the new value and release on the old value (if any). You're doing it correctly in this code sample, but if elsewhere you're assigning straight to allTags (without the self.), you're not releaseing the old value, which may be the source of the leak. Likewise for selectedTags.
Have a look at findByFavoriteId is there a retain there? That is the only difference I can see between the aTags and sTags are used in your example