Lazy Load Property in iOS 5+ with ARC - ios

Problem
I am migrating some legacy code (pre iOS 5) where I lazy load some readonly properties. I want to update this code to iOS 5+ with ARC. But I just learning about ARC.
.h
#property (nonatomic, retain, readonly) NSDateFormatter *timeFormatter;
.m
- (NSDateFormatter *)timeFormatter {
if (timeFormatter == nil) {
timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"h:mm a"];
}
return timeFormatter;
}
What I tried
I have tried to simply update my code, but receive an: Assignment to readonly property.
.h
#property (nonatomic, strong, readonly) NSDateFormatter *timeFormatter;
.m
- (NSDateFormatter *)timeFormatter {
if (self.timeFormatter == nil) {
self.timeFormatter = [[NSDateFormatter alloc] init];
[self.timeFormatter setDateFormat:#"h:mm a"];
}
return self.timeFormatter;
}
I also reviewed:
ios ARC strong and alloc
Thread safe lazy initialization on iOS
http://www.cocoanetics.com/2012/02/threadsafe-lazy-property-initialization/
Question
What is the correct way to lazy-load a readonly property in iOS 5+ with ARC? Would appreciate code samples for both .h and .m.

For a custom (lazy) getter method you have to access the instance variable directly (whether you use ARC or not). So you should synthesize the property as
#synthesize timeFormatter = _timeFormatter;
Then your getter method is
- (NSDateFormatter *)timeFormatter {
if (_timeFormatter == nil) {
_timeFormatter = [[NSDateFormatter alloc] init];
[_timeFormatter setDateFormat:#"h:mm a"];
}
return _timeFormatter;
}
You only have to add some synchronization mechanism if the property is accessed from multiple threads concurrently, that is also independent of ARC or not.
(Remark: Newer Xcode versions can create a #synthesize statement automatically and use the underscore prefix for instance variables. In this case however, since the property is read-only and you provide a getter method, Xcode does not synthesize the property automatically.)
ADDED: Here is a complete code example for your convenience:
MyClass.h:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#property (nonatomic, strong, readonly) NSDateFormatter *timeFormatter;
#end
MyClass.m:
#import "MyClass.h"
#implementation MyClass
#synthesize timeFormatter = _timeFormatter;
- (NSDateFormatter *)timeFormatter {
if (_timeFormatter == nil) {
_timeFormatter = [[NSDateFormatter alloc] init];
[_timeFormatter setDateFormat:#"h:mm a"];
}
return _timeFormatter;
}
#end
MORE INFORMATION: In fact, your pre-ARC timeFormatter getter method works without changes also with ARC, if the property is synthesized as
#synthesize timeFormatter; // or: #synthesize timeFormatter = timeFormatter;
The only "mistake" you made was to replace timeFormatter by self.timeFormatter inside the getter method. This creates two problems:
Reading self.timeFormatter inside the getter method leads to infinite recursion.
Setting self.timeFormatter is not allowed because of the read-only attribute.
So if you just leave the timeFormatter getter method as it was (using the timeFormatter instance variable inside the method) then it works also with ARC.
I would still recommend to prefix instance variables for properties with an underscore as in my code example, because Xcode does it the same way for automatically synthesized properties.
(I hope that this helps and does not increase the confusion!)

Readonly properties are just that: read only. There should be no setters involved. The nice part is, if you redeclare the variable in a class extension (usually with a pair of empty parenthesis), as readwrite (or even just remove the readonly entirely), then you can assign to it within the .m, but classes that import it will see it as readonly.
#interface MyClass ()
#property (nonatomic, strong) NSDateFormatter *timeFormatter;
#end
This redeclaration allows a cleaner way to access and mutate the property internally without resorting to fragile iVar synthesis (which is becoming an antiquity now that the compiler does it for you). You can, or course, still use the iVar as shown in the other answer, but iVar access outside of -init or synthesized getters is unnecessary.*
*As Martin correctly pointed out, even if your assignment had succeeded, you still would have caused an infinite recursion, so iVar access is necessary, unless you explicitly declare a getter, then you may use property access.

Related

Properties in Objective C (readwrite for self and readonly for others)

In a iOS app, I needed a property which is readonly for other classes but readwrite for self calls. So I followed this question and formed my code as,
In .h:
#interface TheClassName : NSObject {
NSString* str;
}
#property(nonatomic, retain, readonly) NSString* str;
#end
In .m:
#interface TheClassName()
#property(nonatomic, retain, readwrite) NSString* str;
#end
#implementation TheClassName
-(id)init {
if(self = [super init]) {
str = [[NSString alloc] initWithString:#"hello"];
}
return self;
}
#end
This procedure is valid also according to Apple Documentation. But I tried experimenting on my code and the problem started.
All I did is ignored the #interface part in the .m file with respect to Seva Alekseyev's answer here, but compiler showed no warning or error when I used it as str = [[NSString alloc] initWithString:#"hello"] in the .m file !!
I mean, the property is set to be readonly, so the statement should have produced an error, but it didn't. WHY??
NOTE: I am using Xcode 5.1.1
This code:
str = [[NSString alloc] initWithString:#"hello"];
doesn't call the property setter, it references the instance variable you defined directly:
#interface TheClassName : NSObject {
NSString* str;
}
and, by default, the backing instance variable will be called _str, so you should remove that instance variable definition and refer to _str directly (if you don't want to create a readwrite version of the property). As it currently stands the property str won't refer to the instance variable str without explicitly using a #synthesize str = str; statement.

Object initialization style [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Imagine my class has following ivars/properties:
#property (nonatomic, copy) NSString *itemName;
#property (nonatomic, copy) NSString *serialNumber;
#property (nonatomic) int valueInDollars;
#property NSDate *dateCreated;
1) One way to initialize ivars of this class is like this:
// Designated initializer of this class
-(id) initWithItemName: (NSString*) name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber
{
// Call the superclass's designated initializer
self = [super init];
if(self)
{
// Init properties
self.itemName = name;
self.serialNumber = sNumber;
self.valueInDollars = value;
dateCreated = [[NSDate alloc] init];
}
// Return the address of the newly initialized object
return self;
}
2) Another way I am thinking go initialize this class is for example is to write:
-(id) init
{
self = [super init];
if(self)
{
// basically do nothing
}
return self;
}
And then leave it up to the user who will be using the class to do initialization as he needs it, e.g.,
MyClass *object = [[MyClass alloc] init];
object.dateCreated = [[NSDate alloc] init];
[object.dateCreated someMethod];
object.itemName = "Hello";
object.someProperty = [[SomeClass alloc] init];
The thing with above I think is that some properties (as above) must be called a alloc/init before they can be used isn't it? And if user forgets to do so, then at most the app won't work as expected right? (It won't crash as we can send message to nil). What I wrote here seems to be the only problem with this way of initialization. What is your opinion?
ps. it is permitted as here too: http://developer.apple.com/library/ios/#documentation/general/conceptual/CocoaEncyclopedia/Initialization/Initialization.html
pps. Assuming ARC is used.
thanks for many replies, but basically I was interested in what are the possible problems with solution 2?
I think you'll find the answer in the document that you linked to:
Overriding init is fine for subclasses that require no additional data to initialize their objects. But often initialization depends on external data to set an object to a reasonable initial state.
So if your class is not in a reasonable state if the variables are not initialised to a proper value, you should use
- (id)initWithItemName:(NSString*)name valueInDollars:(int)value serialNumber:(NSString *)sNumber
Then in init you could either call your designated initialiser with default values, or if there are no reasonable default values disallow the use of init as described here on SO
I'd advise you to create a factory method that calls to the init method in order to combine allocation and initialization in the same step and also hiding the details of the initialization.
#interface CCAttachment()
#property (readwrite, strong, nonatomic) NSString *urlString;
#property (readwrite, strong, nonatomic) NSString *baseURLString;
#property (readwrite, strong, nonatomic) NSData *data;
#property (readwrite, strong, nonatomic) id object;
#property (readwrite, strong, nonatomic) AFHTTPClient *client;
#end
#implementation CCAttachment
//Init method
- (id)initWithURLString:(NSString *)aURLString baseURLString:(NSString *)aBaseURLString
{
self = [super init];
if (self)
{
self.urlString = aURLString;
self.baseURLString = aBaseURLString;
}
return self;
}
//Factory method
+ (instancetype)attachmentWithURLString:(NSString *)aURLString baseURLString:(NSString *)aBaseURLString
{
return [[self alloc] initWithURLString:aURLString baseURLString:aBaseURLString];
}
#end
They will provide a more uniform interface for creating instances. For example, if you later want to convert the above object to an nsmanagedobject, you would keep the same factory method and only change its implementation
+ (instancetype)attachmentWithURLString:(NSString *)aURLString baseURLString:(NSString *)aBaseURLString
{
CCAttachment *result = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self.class) inManagedObjectContext:MOC];
result.urlString = aURLString;
result.baseURLString = aBaseURLString;
return result;
}
http://developer.apple.com/library/ios/#documentation/general/conceptual/CocoaEncyclopedia/ClassFactoryMethods/ClassFactoryMethods.html
As #Kreiri said - Depedns... But I think that if you want to prevent some stupid errors/mistakes you should give a user a tool called designated initializer. The less possibilities to crash the better your code is!
You should try to initialize ivars by yourself to prevent any type of crash. 1st approach bounds the user to input all parameters, and is safe. 2nd approach can cause crash a you mentioned yourself, but you can be on safe side if you initialize variables yourself in 2nd approach.
-(id) init
{
self = [super init];
if(self)
{
itemName = #"";
serialNumber = #"";
valueindollars = -1;
dateCreated = nil;//Better than garbage
}
return self;
}
As a good programming practice, you should initialize objects to nil to avoid access to any garbage value.
You should make yourself familiar with the basics of Object Oriented Design.
Generally, an instance of a class SHALL fulfill a crisp defined invariant after it has been created. That means, your instance (that includes all ivars) SHALL be in a particular, logical correct state after it has been initialized.
It's also required that after responding to any message the instance MUST still fulfill its invariants. This state may be different than before responding to the message, but it MUST still in a reasonable state.
Form your second design, a user can set and read any ivar at any time through the properties. Now suppose, your instance also responds to other messages which you have defined as methods in your class.
And now answer that question: is it guaranteed that at any time an instance of your class is in a state which fulfills the invariant conditions and thus can always respond to any messages in a clear and defined manner?
You will realize, that in the second approach, this is only the case when your class just serves as a container for the four ivars, and has effectively no other responsibilities. So, one should ask what's then the purpose of the class at all? ;)
As a general principle, it is bad style to create an object with an invalid state, because the user may forget that he has to set a valid state for some variable before using it.
Sometimes there are too many possible arguments, which would make the classical pattern (sometimes called “telescoping constructor”) cumbersome. Think of pizza ingredients for example initPizzaWithPepperoni:tomate:mozzarella:...etc. For this cases, you can use a builder pattern.
This example from “Effective Java” illustrates three different ways to initialize an object
builder: useful when there are too many possible arguments or their combinations are complex.
bean
“telescoping constructor”
main.m
int main(int argc, char *argv[]) {
#autoreleasepool {
NutritionFacts *facts = [NutritionFacts new];
// builder
facts = [[[[facts builder] calories:100] sodium:35] build];
// bean constructor pattern
facts.calories=100;
facts.sodium=35;
// telescoping constructor pattern
// [[NutritionFacts alloc] initWithCalories:100];
// [[NutritionFacts alloc] initWithCalories:100 sodium:35];
}
}
NutritionFacts+Builder.m
#interface NutritionFacts(Builder)
-(NutritionFactsBuilder*)builder;
#end
#implementation NutritionFacts(Builder)
-(NutritionFactsBuilder*)builder {
return [[NutritionFactsBuilder alloc]initWithNutritionFacts:self];
}
#end
NutritionFacts.m
#interface NutritionFacts : NSObject
#property (nonatomic, assign) NSUInteger calories, carbohydrate,
cholesterol, fat, fiber, protein, saturatedFat, sodium;
#end
#implementation NutritionFacts
#end
NutritionFactsBuilder.m
#interface NutritionFactsBuilder : NSObject
-(id)initWithNutritionFacts:(NutritionFacts*)facts;
#end
#implementation NutritionFactsBuilder {
NutritionFacts *_facts;
}
-(id)initWithNutritionFacts:(NutritionFacts*)facts {
self = [super init];
if (self){
_facts = facts;
}
return self;
}
-(BOOL)isValid {
// ... check valid ivar combos
NSAssert(YES,#"Always valid");
}
-(NutritionFacts*)build {
[self isValid];
return _facts;
}
-(instancetype)calories:(NSUInteger)calories {
_facts.calories = calories;
return self;
}
-(instancetype)sodium:(NSUInteger)sodium {
_facts.sodium = sodium;
return self;
}
// ...
#end

NSString working once then not working

This is my first time using this site and I am quite new to Objective-c. I'm sure this is a simple question but for some reason I am having a lot of issues. The app is designed to have the user enter a string via textfield, then it will pick the rest of the sentence and display it. The issue appears to be that my *name will be retained after the keyboard method and work once in the changelabel method. Then if i press the button again, invoking the changelabel method, the name appears to have been released and crashes the app.
#import
#import "Array.h"
#interface RandomBoredViewController : UIViewController {
UILabel *label;
UIButton *button;
UITextField *textField;
Array *array;
NSString *name;
NSString *description;
NSMutableString *whole;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#property (nonatomic, retain) IBOutlet UIButton *button;
#property (nonatomic, retain) IBOutlet UITextField *textField;
#property (nonatomic, retain) Array *array;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, retain) NSMutableString *whole;
-(IBAction) keyBoard;
-(IBAction) changeLabel;
#end
and my .m
#import "RandomBoredViewController.h"
#implementation RandomBoredViewController
#synthesize label;
#synthesize checker;
#synthesize button;
#synthesize textField;
#synthesize array;
#synthesize name;
#synthesize description;
#synthesize whole;
-(IBAction) changeLabel {
NSLog(#"Button being pushed");
description = [array getString];
NSLog(#"%#",description);
NSLog(#"%#",name);
name = [NSString stringWithString:name];
whole = [NSMutableString stringWithString:name];
NSLog(#"%#",name);
NSLog(#"%#",whole);
[whole appendString:description];
NSLog(#"%#",name);
NSLog(#"%#",whole);
label.text = whole;
NSLog(#"%#",name);
}
-(IBAction) keyBoard {
name = [NSString stringWithString:textField.text];
NSLog(#"%#",name);
label.text = [NSString stringWithString: name];
[textField resignFirstResponder];
}
- (void)viewDidLoad {
[super viewDidLoad];
array = [[Array alloc]init];
[array createArray];
NSLog(#"%i",[array arrayCount]);
whole = [[NSMutableString alloc]init];
name = [[NSString alloc]init];
}
- (void)dealloc {
[super dealloc];
[label release];
[button release];
[textField release];
[array release];
//[name release];
[description release];
}
#end
You are setting name to an autoreleased instance of NSString, this is probably what's causing your app to crash.
Use
self.name = [NSString stringWithString:textField.text];
Your synthesized mutator will retain the NSString and prevent it from being released.
Taking one thing in microcosm, the code you've posted creates two things named name — an instance variable and a property.
Instance variables are directly accessed storage. They have no behaviour.
Properties are named attributes accessed via getters and setters. So they may have arbitrary behaviour. They may report the values of instance variables or values calculated from instance variables or values calculated or obtained by any other means. Relevantly, the setters may retain, assign or act in any other way.
Instance variables may be accessed only by the instance of a class they belong to. Properties are usually intended to be accessed by anyone.
Since retaining is a behaviour and you've ascribed it to your name property, setting something to it would result in a retain. Instance variables can't have behaviour, so setting a value to it doesn't result in a retain or anything else.
As a result, this line:
name = [NSString stringWithString:name];
Creates a new string and returns a non-owning reference. Which means it'll definitely last for the duration of this autorelease pool (ie, you explicitly may pass it as an argument or return it safely, assuming you haven't taken manual control of your autorelease pools).
You store that reference to your instance variable. Instance variables don't have behaviour so the reference is stored but you still don't own that object. It's still only safe to use for the duration of that autorelease pool.
So when you access it in that method it's safe. When you access it later it's unsafe.
If instead you'd gone with:
self.name = [NSString stringWithString:name];
Then you'd have set that string to be the new value of the property. Because your property has the retain behaviour, you'd subsequently have completely safe access to the string object, until you say otherwise.
Because you've got a property with exactly the same name as an instance variable, you could subsequently access it either as just name or as self.name. Similarly you could have stored directly to the instance variable rather than via the property if you'd ensured you had an owning reference manually.
As suggested above, use of ARC is a way to get the compiler to figure all this stuff out for you.
That issue is what causes your code to crash — you end up trying to access a reference that has ceased to be valid. If you'd taken ownership of it then it would have continued to exist at least as long as you kept ownership.
try using self.name
sometimes this stuff confuses me as well and for that you might want to consider using arc in which case most of this stuff can be avoided.
when using properties you should always use self.propertyName vs propertyName (only), it uses the accessors (get propertyName, set propertyName) as opposed to directly accessing that pointers value.
take in mind there are 2 exceptions to the rule, init and dealloc which should NOT use self.
self.name = [NSString stringWithString:name];
you technically should also have an init method
to initialize your variables, and i believe you should call [super dealloc] last not first in your dealloc method, but thats not your problem and might not matter (just what I do when I dont use arc)
When you change your instance variable in changeLabel, you should release the previous value and retain the new one. You may use the accessors to perform the memory management stuff for you. Also, I think you should invoke [super dealloc] after releasing the instance variables in your implementation of dealloc.
If you're not familiar with Cocoa memory management (and even if you are), the best is to enable ARC (Automatic Reference Counting) and let the compiler deal with it.

Another Memory Management Issue

My app runs well until I stop it and restart - whereupon the archive file - highScores.archive is present. Then, the app balks at encoding - I get a EXC_BAD_ACCESS at the first line (for a long time, it didn't happen until I got to the date object I was encoding.
My guess is that I need to put in a retain in a couple of places, but I don't know where.
The code:
FlipHighScores.h
...
#interface FlipHighScores : NSObject <NSCoding> {
//NSString *themeChosen;
NSInteger newHighScore;
NSInteger newScoreStartLevel;
NSInteger newScoreFinishLevel;
NSDate *scoreDateCreated;}
#property (copy, nonatomic) NSString *themeChosen;
#property (nonatomic) NSInteger highScore;
#property (nonatomic) NSInteger scoreStartLevel;
#property (nonatomic) NSInteger scoreFinishLevel;
#property (nonatomic, readonly, strong) NSDate *scoreDateCreated;
...
FlipHighScores.m
...
#synthesize themeChosen = _themeChosen;
#synthesize highScore = _highScore;
#synthesize scoreStartLevel = _scoreStartLevel;
#synthesize scoreFinishLevel = _scoreFinishLevel;
#synthesize scoreDateCreated = _scoreDateCreated;
...
-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_themeChosen forKey:#"_themeChosen"];
NSLog(#"Theme Chosen is %#", _themeChosen);
[aCoder encodeInt:_highScore forKey:#"_highScore"];
[aCoder encodeInt:_scoreStartLevel forKey:#"_scoreStartLevel"];
[aCoder encodeInt:_scoreFinishLevel forKey:#"_scoreFinishLevel"];
NSLog(#"Date Created in encodeWithCoder is %#", _scoreDateCreated);
[aCoder encodeObject:_scoreDateCreated forKey:#"_scoreDateCreated"];}
-(id)initWithCoder:(NSCoder *)aDecoder {
if (self) {
_themeChosen = [aDecoder decodeObjectForKey:#"_themeChosen"];
_highScore = [aDecoder decodeIntForKey:#"_highScore"];
_scoreStartLevel = [aDecoder decodeIntForKey:#"_scoreStartLevel"];
_scoreFinishLevel = [aDecoder decodeIntForKey:#"_scoreFinishLevel"];
_scoreDateCreated = [aDecoder decodeObjectForKey:#"_scoreDateCreated"];
}
return self;}
-(NSString *)description {
NSDate *date = _scoreDateCreated;
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
NSString *dateString = [dateFormatter stringFromDate:date];
//NSLog(#"dateString from description is %#", dateString);
NSString *descriptionString = [[NSString alloc] initWithFormat:#"%d %# S:%d F:%d D:%#", _highScore, _themeChosen, _scoreStartLevel, _scoreFinishLevel, dateString];
return descriptionString:}
What I find confusing is that if I delete the save file - highScores.archive and run the app, it runs without problem. I stop and kill the app and then start it again - the first time encoding is called it crashes.
At the line where I encode the themeChosen object. I have read a few posts about decoding issues being fixed with a "retain" or changing to . format (why that would help, I don't really understand). But this is encoding. Decoding will probably be the next question...
I am not using ARC on this project. Maybe when I rebuild the whole thing from scratch...
Oh, I forgot to mention that everything was running smoothly as far as I had tested until I added in tracking the Theme variable. Then things went a smidge awry as mentioned here.
I think your problem is in your -initWithCoder. You're taking the result of -decodeObjectForKey: and directly assigning it to the synthesized ivar. Methods that don't have the word "copy" in their names are generally assumed to return autoreleased objects.
If you directly assign an autoreleased object to a variable, that object will be released in the next run loop, will dealloc itself, and now your variable points to junk memory. When you try to access it, you'll get an exec_bad_access.
What you should be doing is taking advantage of the accessor methods that #synthesize creates for you. Instead of
_themeChosen = [aDecoder decodeObjectForKey:#"_themeChosen"];
you should write
[self setThemeChosen:[aDecoder decodeObjectForKey:#"_themeChosen"]];
or, if you positively must use an equal sign, you could use the syntactic sugar of "dot notation":
self.themeChosen = [aDecoder decodeObjectForKey:#"_themeChosen"]
Which will ultimately be translated into close to the same thing.
The key is: the synthesized setter does more than simply assign the object to the ivar. It also retains the object (actually, in this case, it copies the object because you specified copy in your #property declaration). This is only one of the many, many, many reasons you should never access ivars directly and always use accessors -- especially now that they're essentially written for you automagically by #property/#synthesize.
UPDATE:
You're going to find you have trouble with scoreDateCreated seeing as you declared it as being readonly in its #property declaration. Why's it read only? It doesn't appear to be a derived value, so you're clearly going to have to assign something to it.
If you want it read/write in your object, but only want to expose a read only interface, you can redeclare the #property as read/write in an anonymous category at the top of FlipHighScores.m. So it looks read only to anything that includes the header, but is actually read/write inside your object's implementation.

Instruments Leaks shows non-existent method call

Either I don't understand the Instruments Leaks tool at all, or I am going mad. I have run the tool on my iphone app, and it shows a couple of leaks. If I understand it correctly, for one of the leaks, it says that it is an NSDate object allocated by my method "writeHeading". The method that allocates the object is: "dateWithTimeIntervalSinceReferenceDate:". However, my writeHeading method does not use that method. In fact, that method is not used anywhere in my whole application.
Does anybody have an idea what could be going on here?
Here is the code of writeHeading:
- (void) writeHeading:(CLHeading *)heading
{
if (self.inFlight) {
[log writeHeading:heading];
} else {
IGC_Event *event = [[IGC_Event alloc] init];
event.code = 'K';
event.timestamp = heading.timestamp;
event.heading = heading;
[self addEvent:event];
[event release];
}
}
Here is a screenshot of Instruments:
And here is the definition of IGC_Event (as asked by multiple responders):
#interface IGC_Event : NSObject {
int code;
CLLocation *location;
CLHeading *heading;
NSString *other;
NSDate *timestamp;
}
#property int code;
#property (nonatomic, retain) CLLocation *location;
#property (nonatomic, retain) CLHeading *heading;
#property (nonatomic, retain) NSString *other;
#property (nonatomic, retain) NSDate *timestamp;
#end
#implementation IGC_Event
#synthesize code;
#synthesize location;
#synthesize heading;
#synthesize other;
#synthesize timestamp;
#end
Assuming no ARC, you need to make sure IGC_Event objects release their timestamp and other references that may have been retained or copied.
So in IGC_Event you need a dealloc something like this:
- (void) dealloc {
[timestamp release];
[location release];
[heading release];
[other release];
[super dealloc];
}
Leaks is just telling you where that timestamp object was created, not where you should have released it.
That may not be the only place you are leaking of course, but that's 4 potential leaks right there.
When the compiler runs your code, there are the methods directly called by you (which in your screenshot have a little person next to them) and then the methods that are invoked in the core frameworks as a result. The method in question results from this piece of code:
event.timestamp = heading.timestamp;
You could manage this process yourself if you wanted to:
NSDate *eventTimestamp = heading.timestamp;
event.timestamp = eventTimestamp;
Incidentally, storing that timestamp is entirely redundant and uses unnecessary memory, since you also store the heading with all its properties in event.heading so at any time you can access that timestamp with event.heading.timestamp. However, you may have other reasons for storing it separately.
Do you have the implementation of the IGC_Event class? Is it possible that the setter for its timestamp property is calling dateWithTimeIntevalSinceReferenceDate:? (Not an unreasonable thing to do, so far as I can tell. That would ensure that its timestamp is of class NSDate itself, and not a subclass. It would also ensure that it's independent of the timestamp that was passed in.)
(Disclaimer: I'm really not much of an Objective-C-er. If this seems like a stupid question, then it probably is!)

Resources