I would like to assign a date from one view controller to another
-(void) setCurrentDate:(NSDate newDate){
self.currentDate = newDate;
[self updateView];
}
While debugging I see the currentDate value out of scope and the application crashes with EXC_BAD_ACCESS.
Any help will be appreciated.
Besides that your setter should take NSDate by pointer (all class-type instances are passed by pointer in Objective-C), you are recursively calling the setter:
self.currentDate = foo results in [self setCurrentDate:foo] being called.
Correctly it should look e.g. like this (assuming a nonatomic, retain property):
- (void)setCurrentDate:(NSDate *)newDate {
if (currentDate != newDate) {
[currentDate release];
[newDate retain];
currentDate = newDate;
[self updateView];
}
}
Alternatively name that method different from the setter so you can use the synthesized setter:
- (void)updateDate:(NSDate *)newDate {
self.currentDate = newDate;
[self updateView];
}
You need to pass the pointer to date. Something like this:
-(void) setCurrentDate:(NSDate* newDate){
[self.currentDate release];
self.currentDate = newDate;
[self.currentDate retain];
[self updateView];
}
Of course, your currentDate class variable should also be a NSDate pointer. It will be even better if you use a property instead of a custom made setter.
Possibly, you need to retain newDate or copy it, if it's possible.
What I mean:
You create newDate
You call setCurrentDate
You release newDate
[self updateView] try to use it and fails because it is already released.
You also can try NSZombieEnabled to catch this kind of bugs.
In your method name, you use (NSDate date). You forgot to include the "*", which makes it a pointer. The correct code should be
-(void) setCurrentDate:(NSDate *newDate){ // Notice the star after NSDate
self.currentDate = newDate;
[self updateView];
}
Related
Tested app in Instrumens for memory leak getting multiple leaks for using multiple times pauseTimer and resumeTimer.
Defined in m file
NSDate *pauseStart, *previousFireDate;
-(void)pauseTimer{
pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain];
previousFireDate = [[timer fireDate] retain];
[timer setFireDate:[NSDate distantFuture]];
}
-(void)resumeTimer{
float pauseTime = -1*[pauseStart timeIntervalSinceNow];
//[timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];
[timer setFireDate:[NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate]];
}
how to fix this memory leak for pauseTimer and resumeTimer. User can use PauseTimer and resumeTimer multiple times.
Appreciate help.
Thanks.
You are retaining the values for pauseStart and previousFireDate each time the pauseTimer method is fired. You need to release the previous values before retaining the new values in order to avoid a memory leak.
Easiest solution is to create two retained properties for those values (possibly in a class extension), so when you set new values, the release is handled for you. (Just don't forget to release the values in your dealloc method to also avoid leaks.)
You can use NSTimer's isValid property and invalidate method.
-(void)pauseTimer
{
if ( !timer.isValid )
return;
// remember your fire date
[timer invalidate];
}
-(void)resumeTimer
{
if ( timer.isValid )
return;
// schedule your timer to new date
// release old date
}
Did any body get this issue?
If I need an instance variable, not as a property, and initialize this variable in a method, then when I need it, it is already released. It happens for autoreleased objects. What is the reason for this?
Usually instance variable should have the whole lifetime of the class object. But it seems if the variable is local to a function, and its a autorelease object, it is released when the function exits.
MyClass.h
#interface MyClass:UIViewController {
NSDate * date;
}
MyClass.m
#implementation MyClass {
- (void) anInit {
date = [NSDate date];
}
- (void) useDate {
NSLog (#"%#", date);
// here date is already release, and get bad access.
}
}
You need to retain date.
An autoreleased object will be released when the autorelease pool is next drained. When this happens has nothing to do with the lifecycle of your object.
Your implementation should look like this:
#implementation MyClass {
- (void) anInit {
date = [[NSDate date] retain]; // or [[NSDate alloc] init]
}
- (void) useDate {
NSLog (#"%#", date);
}
- (void) dealloc {
[date release];
[super dealloc];
}
}
[NSDate date] is a Convenience Constructor and is autoreleased, you need to add a retain call. Also make sure anInit is only called once or you will create a memory leak without calling [date release] first.
- (void) anInit {
date = [[NSDate date] retain];
}
I post this question again but with more precision this time,
first, I have this function who return a string, there is some error about memory management or this fonction is ok?
-(NSString *) motAvecCle:(NSString *) cle
{
NSString *motRetour;
motRetour = #"";
cle = [FonctionUtile concatener:[[tableauConfig singletonTableauConfig] langueAffichage] chaine2:#"_" chaine3:[FonctionUtile trim:[cle uppercaseString]] chaine4:#""];
motRetour = [FonctionUtile trim:[dictionnaireLangue objectForKey:cle]];
if (motRetour == nil) {
motRetour = #"Erreur";
}
return motRetour;
}
and when I call this fonction,
NSString *myString = #"";
myString = [self motAvecCle:#"fr"]; // I must do this?
myString = [[self motAvecCle:#"en"]retain]; //or do this?
thx again...
The method motAvecCle: returns an object you do not own. Therefore, at some point it is going to disappear. Whether you care or not depends on where myString is defined. If it's in the same scope:
-(void) foo
{
NSString *myString = [self motAvecCle:#"fr"];
// do some stuff
}
you do not want to retain it (except in one circumstance) because the reference will disappear when foo exits which means if you had retained it you'd need to release it again first.
The one circumstance for retaining is if you modify the object you got the string from i.e. self in this case. That might cause the string to go away (although probably not in your specific example).
If myString is an instance variable of the object, you do want to retain it because otherwise it will disappear (possibly) the next time the auto release pool is drained. However, before assigning the instance variable, you must be sure to release the old value of the instance variable, unless it's actually the same string you are assigning i.e. you need to do something like this:
-(void) foo
{
NSString *tmp = [[self motAvecCle:#"fr"] retain]; // it's a string, technically you should copy, not retain
[myString release];
myString = tmp;
// do some stuff
}
Since you'd have to do that every time you want to assign the ivar, it's normal to create an accessor e.g.
-(void) setMyString: (NSString*) newValue
{
NSString* tmp = [newValue copy];
[myString release];
myString = tmp;
}
-(void) foo
{
[self setMyString: [self motAvecCle:#"fr"]];
// do some stuff
}
If you use properties, you can use #synthesize to create the accessors.
I am trying to compare two NSDates one is created by the viewDidLoad method and the other by clicking a button. I want to be able to click the button and find the time difference since the viewDidLoad was ran. I keep getting a difference of nil. Any Ideas?
#import "TimeViewController.h"
id startTime;
#implementation TimeViewController
- (void)viewDidLoad {
NSDate *startTime = [NSDate date];
NSLog(#"startTime = %#",startTime);
}
- (IBAction)buttonPressed{
NSDate *now = [NSDate date];
NSLog(#"now = %#",now);
double timeInterval = [now timeIntervalSinceDate:startTime];
NSLog(#"time difference = %#",[NSString stringWithFormat:#"%g",timeInterval]);
}
You have
id startTime;
in the global scope, and also
NSDate *startTime = [NSDate date];
inside viewDidLoad. The second statement creates a local variable called startTime, which hides the global variable. Use
startTime=[[NSDate date] retain];
instead.
That said, I'd suggest you not to create the global variable. Instead, make it an instance variable and a property:
#interface TimeViewController :NSObject{
....
NSDate*startDate;
}
...
#end
and as Kubi said, don't forget
-(void)dealloc{
[startDate release];
[super dealloc];
}
I'd also suggest not to use id to hold a known object. Who told you that? That's a very bad practice. Even when you declare a global variable, you should use
NSDate*startDate;
so that the compiler can warn you against non-defined methods.
memory management still gives me grief. This time it is an NSDate iVar that I init using
NSDate *myNSDate = [[NSDate date] firstDayOfMonth];
with a method call to
- (NSDate *)firstDayOfMonth {
NSDateComponents *tmpDateComponents = [[NSCalendar currentCalendar]
components:NSYearCalendarUnit | NSMonthCalendarUnit | NSEraCalendarUnit | NSWeekCalendarUnit | NSWeekdayOrdinalCalendarUnit
fromDate:self];
[tmpDateComponents setDay:1];
[tmpDateComponents setHour:0];
[tmpDateComponents setMinute:0];
[tmpDateComponents setSecond:0];
return [[NSCalendar currentCalendar] dateFromComponents:tmpDateComponents];
}
At the end of the init call the retain count is at 1 (Note the iVar is not defined as a property).
When I step into the viewWillAppear method the myNSDate has vanished. I tried to do an explicit retain on it, but that only lasts until I update the iVar using the above method again.
I though - ok - I add the retain to the return of the function, but that makes the leak analyser throw up an error.
What am I doing wrong?
Your method firstDayOfMonth is correct as it is given in your question. However, the return value of that method is an autoreleased date, which means that if you don't retain the return value somewhere else, it will disappear.
So you need to do something like this (assuming your ivar is named firstDayOfMonth:
- (id) init {
if (self = [super init...]) {
...
[self setFirstDayOfMonth:[[NSDate date] firstDayOfMonth]];
}
return self;
}
- (void) setFirstDayOfMonth:(NSDate *)newFirstDay {
[firstDayOfMonth release];
firstDayOfMonth = [newFirstDay retain];
}
- (void) dealloc {
[firstDayOfMonth release];
...
[super dealloc];
}
In this, you're explicitly retaining the return value (but also making sure to release the old value so you're not leaking memory). Now your date object will live until you set a new date, or the object is deallocated and the date is destroyed in the dealloc method.