Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Slick's Definitive Guide To Properties

24

Replies

  • MikeTheCatMikeTheCat Posts: 24Registered Users
    edited April 2010
    I'm studying your article and appreciating how clearly you're describing the issues. I'm writing my first iPhone app and I'm new to C and the Mac, so I'm surprised that my app doesn't reveal any memory leaks in Instruments or in the Clang Static Analyzer.

    But since I'm still not sure what I'm doing, I'm chasing down every little thing that is confusing or different from what I "learned" elsewhere.

    In the case at hand, your Fig. 2 shows this:

    @synthesize myProperty=myInstanceVariable;

    but I don't know why you don't just do:

    @synthesize myInstanceVariable;

    I'm using SDK 3.1.3 on Leopard.
  • MikeTheCatMikeTheCat Posts: 24Registered Users
    edited April 2010
    In another thread here:

    http://www.iphonedevsdk.com/forum/iphone-sdk-development/2374-property-synthesize.html

    Jeff Lamarche wrote this:

    "Personal preference, but on the iPhone I use them. On the Mac, not so much, only because if you use them, people on older versions of OS X (pre-Leopard) can't run your program. For new programs, though, I use them, they're awfully convenient compared to building accessors and mutators, and they make it much easier to get your memory management right because you can specify (retain) in the property's attributes and it handles retaining and releasing the objects you assign. "

    Should I understand that to mean that as long as I never use dot-syntax for instance variables (that have properties and are synthesized), I don't have to do anything beyond the release in the dealloc?
  • smithdale87smithdale87 Posts: 4,447iPhone Dev SDK Supporter @ @ @ @ @
    edited April 2010
    You can do this if you want the property name to be different from the instance variable name.
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited April 2010
    That's a matter of choice. The property and the instance variable can have the same name. However, even if they do have the same name, it is crucial to remember that you're talking about two distinct kinds of entities.

    It is for this reason that a variety of naming conventions exist for identifying instance variables. You might see _instanceVariable or myInstanceVariable. I'm personally changing my style to use ivInstanceVariable. These are ways to visually distinguish the instance variable from the property.

    For a while I was using the same name for both, and relying on the color scheme previously mentioned to sniff out any inadvertent use of instance variables. I'm comfortable enough with my own techniques to be confident that I'm always using the property anyway, so the specifics of the name don't really matter to me. But, when it comes to copy-pasting code, I lose the color scheme. Or when viewing code from other people who use dot-syntax, the color scheme still shows as though it is an instance variable even though it is correct use of a property. So I'm leaning more and more towards recommending distinct names between instance variables and properties.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • MikeTheCatMikeTheCat Posts: 24Registered Users
    edited April 2010
    Thanks for yet another clarification. It seems like I'd be better off naming them differently, so I'll do a bunch of refactoring.

    And I just bought your app and I see it in iTunes on my MacBook Pro, but unlike the one's I selected right from my Touch, I don't know how to get it from iTunes to the Touch. (I realize this is off-topic.)

    - Forget that n00b question. I figured out how to select my Touch in iTunes and trigger a sync of the apps.
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited April 2010
    MikeTheCat wrote: »
    Should I understand that to mean that as long as I never use dot-syntax for instance variables (that have properties and are synthesized), I don't have to do anything beyond the release in the dealloc?

    Sorry, didn't see this before.

    I'm not entirely sure I understand what you're asking. Dot-syntax does not apply to instance variables. It is a notation for accessing properties - the getter and setter methods for talking to a particular instance variable.

    I don't like dot-syntax when compared to bracket-syntax. But either way you are using the properties, and that's good.

    These are very different:
    self.variable = ...;
    variable = ...;
    

    The first is a method call. The second is direct access to the instance variable. This first is equivalent to:
    [self setVariable:...];
    
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • MikeTheCatMikeTheCat Posts: 24Registered Users
    edited April 2010
    Again you have made it clear why I should be using different names for instance variables and properties, because my confusion was due to them being named the same in the code I was looking at. This caused me to ask a question which in fact didn't make any sense. Sure glad I asked it anyway and now (I'm pretty sure) you've straightened me out.

    Of course, now I've now got to wrap my mind around still more. For instance, I continually see tutorials in which an i-v is created, and then a corresponding @property is created, followed by the @synthesize in lock-step. This seems to have given rise to my misimpression that the creation of the getters/setters with synthesize ties them back THROUGH the property all the way back to the i-v. This wouldn't have happened if the i-v and properties had different names. If that represents a new incremental decrease in misunderstanding, then it leaves me wondering why both i-v and property are created. If they're two separate things, why do we need both? Is one dependent on the other?

    Or, maybe in a short time I'll realize that none of that makes any sense, either.

    - upon re-reading your message, I think I just need to refactor some code before it will really be clear, so you might want to ignore this message until I edit it again when I really have something sensible to ask.
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited April 2010
    Well, see Figure 3.

    I'm not sure how fundamental to go, so let's briefly talk about scope.
    - (void)someMethod
    {
       NSArray *anArray = ...;
    
       // More code
    }
    

    As soon as you hit the last }, the variable anArray can no longer be used. This is a local variable.

    Let's say you need to use anArray in multiple methods. You can't define it within any one method, because the other methods won't know about it. So you declare it in your .h file.
    @interface SomeViewController : UIViewController
    {
       NSArray *anArray;
    }
    

    What this does is make the anArray variable available to your entire class. Any method can use it. Any method can change it.
    - (void)someMethod
    {
       anArray = ...;
    }
    
    - (void)someOtherMethod
    {
       anArray = ...;
    }
    

    Note the lack of NSArray * type declaration here. It's not needed since that was defined in the .h file. So now anybody can talk to that (instance) variable. The scope is now global (at least, within that class), and that's good, but this introduces a whole different set of issues. First and foremost, memory management. Let's say that each of these classes did the exact same thing: created a new array.
    - (void)someMethod
    {
       anArray = [[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil];
    }
    
    - (void)someOtherMethod
    {
       anArray = [[NSArray alloc] initWithObjects:@"D", @"E", @"F", nil];
    }
    

    If we then call these methods in succession from anywhere....
    [self someMethod];
    [self someOtherMethod];
    
    ...let's take a look at what happens. First an array is created, and assigned to our instance variable. Then a second array is created and assigned to that same instance variable. In this particular case, the first array has been leaked.

    And this is a pretty common example of the pitfalls of using instance variables directly. When should an object be released? What if I call those methods in reverse? If the method that created the array also releases it, then the object dies, and that defeats the purpose of making it available for other methods. If another method replaces the object without first releasing the original, that's a leak. If another method releases the object again after it was already released, that is a likely crash candidate. Need a better option.

    So up to this point, we are dealing only with variables: local, and instance. Variables either way, differing only in scope.

    What we want to do is stop talking to the instance variables directly, because it is too easy to make memory management mistakes that way. Instead, we will use a mechanism that sits between us and the instance variable, and the goal of that mechanism is to reduce confusion over memory management responsibilities.

    That mechanism comes in the form of 2 methods: the getter, and the setter. The setter is used to place a new value into the instance variable, and the getter is used to retrieve the value from the instance variable. In simplest form, the getter/setter pair could look like this:
    - (void)setTheValue:(NSArray *)array
    {
       anArray = array;
    }
    
    - (NSArray *)theValue
    {
       return anArray;
    }
    

    I'm still using anArray as an instance variable, but now I have provided some additional means of talking to it. To use these in code, it would look like this:
    [self setTheValue:aLocalVariable];
    -or-
    NSArray *anotherLocalVariable = [self theValue];
    

    Now I'm doing method calls. Before I was doing variable assignments.

    But at this point, what is really different? So far, nothing. If you notice, these methods are doing the exact same thing I was doing before: directly manipulating the instance variable. So what is the point? Ah, but we can make these methods do more stuff.
    - (void)setTheValue:(NSArray *)array
    {
       [array retain];
       [anArray release];
       anArray = array;
    }
    

    What this does now is retain any incoming value, release any old value, and assign the new value to the instance variable. The beauty of this is that it happens every time. No matter which other method calls it, or how many times, setTheValue: will always do the same thing: retain new, release old.

    What I've described up to this point is how life was before Obj-C 2.0. These getter/setter pairs - theValue/setTheValue: - had to be created manually. But they were used widely enough that Apple decided to streamline (and standardize) the process. Thus, @properties entered the language with version 2.

    Before going too much farther, let's step back and remember that the .h file is for declarations, and the .m file is for implementations. So if I was to combine everything up to this point into a single .h file, it would look like this:
    @interface SomeViewController : UIViewController
    {
       NSArray *anArray;
    }
    
    - (void)setTheValue:(NSArray *)array;
    - (NSArray *)theValue;
    - (void)doSomethingUseful;
    

    We define our instance variable, and 2 methods. Then over in the .m file, we would implement these methods:
    @implementation SomeViewController
    
    - (void)setTheValue:(NSArray *)array
    {
       [array retain];
       [anArray release];
       anArray = array;
    }
    
    - (NSArray *)theValue
    {
       return anArray;
    }
    
    - (void)doSomethingUseful
    {
       ...
    }
    
    - (void)dealloc
    {
       ...
    

    The property declaration is merely shorthand for this exact same thing. We take these two:
    - (void)setTheValue:(NSArray *)array;
    - (NSArray *)theValue;
    
    ...and replace them with this:
    @property (nonatomic, retain) NSArray *theValue;
    

    Functionally equivalent, a little bit of streamlining here in the .h file, but not really tons of savings. That happens in the .m file, where we take these:
    - (void)setTheValue:(NSArray *)array
    {
       [array retain];
       [anArray release];
       anArray = array;
    }
    
    - (NSArray *)theValue
    {
       return anArray;
    }
    
    ...and replace them with this:
    @synthesize theValue=anArray;
    

    This is why you see @synthesize tightly coupled with @property. If you declare something in the .h file, you have to implement it in the .m file. That implementation takes the form of @synthesize (though you can still do it the old way, too).

    So, the instance variable is merely a variable that has been declared in the .h file, making it available to the entire class.

    The @property defines 2 methods that are used for talking to that instance variable, in a consistent, memory management friendly way.

    I skipped some details here since they would be a rehash of the earlier posts in this thread, so hopefully the combination will make things clear.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • Duncan CDuncan C Posts: 9,114Tutorial Authors, Registered Users @ @ @ @ @ @ @
    edited April 2010
    BrianSlick wrote: »
    I keep answering similar questions with similar answers, so I'm trying to put this stuff in one place. I'll just start referring people to this thread. Please feel free to offer comments or suggestions, and I'll make corrections where appropriate. I'm open to debate on anything mentioned here, but this is what I do, it works well for me, and is drawn from the advice of significantly more-experienced coders.

    Slick,

    Overall a good tutorial. It should help beginners.

    One thing, though.

    You list an example setter method for a retained property like this:
    - (void)setMyProperty:(MyClass *)newValue
    {
       [myInstanceVariable release];
       myInstanceVariable = [newValue retain];
    }
    


    That's not quite right. It should read:
    - (void)setMyProperty:(MyClass *)newValue
    {
       if (myInstanceVariable != newValue)
       {
          [myInstanceVariable release];
          myInstanceVariable = [newValue retain];
       }
    }
    

    You need to make sure the new value of myProperty is different from the old value before releasing it.

    The issue is this:

    If you end up setting a property to it's current value, the object gets released, probably dies immediately, then you send a retain message to an object which is now dead.

    So, with your setter, if you had code like this:
    anObject* theObject = object.myProperty; //Initialize local variable with starting value.
    
    //Insert code here that may or may not change the value of myProperty
    if (condition)
       theObject = someNewValue;
    
    object.myProperty = theObject;  //Save the result back to the property.
    

    In the code above, if "condition" is false, the myProperty object gets a release, then a retain. If it's retain count is zero, it will be released immediately, and the retain call will probably crash.

    If the myProperty object has received one or more autorelease messages that haven't "popped" yet you might get away with your setter, but it will cause crashes sometimes.


    Regards,

    Duncan C
    WareTo
    Regards,
    Duncan C
    WareTo

    widehead.gif
    Animated GIF created with Face Dancer, available for free in the app store.

    I'm available for one-on-one help at CodeMentor
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited April 2010
    Yes, that's already been addressed, and still isn't the point of the thread.

    Thanks for your input, though.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • Duncan CDuncan C Posts: 9,114Tutorial Authors, Registered Users @ @ @ @ @ @ @
    edited April 2010
    BrianSlick wrote: »
    Yes, that's already been addressed, and still isn't the point of the thread.

    Thanks for your input, though.

    Slick,

    I realize it isn't the main point of the thread. I neither want to detract from an excellent explanation, nor distract from the point of your thread.

    However, posting example code that will cause people's apps to crash in confusing ways is not good form for a tutorial. Thus, your example setter should be well-behaved, because some beginning developer is going to copy and paste it, and have problems.

    I, myself, have thought about writing a tutorial on how to write proper custom getters/setters.

    If you know what you are doing, custom getters and setters can be very powerful. However, there are various pitfalls to avoid. Writing the proper code to support atomic properties is an example of this. Of course, not too many beginning developers write multi-threaded code. Still, it would be good if there was a central source that explained all the various housekeeping you need to do.

    One thing I am not sure about is how you handle KVO notifications in getters/setters. What is standard practice so other objects can observe your properties when you have a custom setter. I'm pretty sure I know what to do, but would like to see it described clearly somewhere.


    Regards,

    Duncan C
    WareTo
    Regards,
    Duncan C
    WareTo

    widehead.gif
    Animated GIF created with Face Dancer, available for free in the app store.

    I'm available for one-on-one help at CodeMentor
  • MikeTheCatMikeTheCat Posts: 24Registered Users
    edited April 2010
    Thanks to your suggestions and guidance, I've re-worked my little app to rename my instance variables so they are different from my property names. This revealed that I had a few cases in which I was referring to an i-v and I've changed them to use the properties.

    This required very little work, but there is a class of cases for which I don't have an equivalent solution. These involve i-v of type NSUInteger and BOOL. Here's an example:

    NSUInteger _currentRow;
    @property (nonatomic, assign) NSUInteger currentRow;

    @synthesize currentRow = _currentRow;

    self.currentRow = 0; // I'm assuming that this is less than ideal

    [self.currentRow setValue:0]; // and it seems that this would work for floats

    setInteger:forKey: // and I figure this is only for key/value pair situations.

    [self.currentRow setWHAT:0]; // but what works for Ints?

    Since I haven't been able to find the information in the docs that show this kind of information, my real question is how to find this info in the docs, but I also wouldn't mind being handed the answer to my specific question of the moment about the setWHAT for an NSUInteger. I'm hoping there is some way of looking at info in the docs that gathers similar functionality together, but so far I just see elemental info for things like NSUInteger and setValue. Is there some organization that is like I've seen in other languages, such as "String manipulation" or something that gathers the set methods for one type like NSUInteger (assuming that such things exist)?

    I'm also assuming there is an OO way of handling the same data in a different way, and I'd also welcome any scolding that includes a suggestion about how to do that, but that's really a subject for a different thread.
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited April 2010
    The naming convention does not depend on the entity types involved. The getter is always "propertyName" and the setter is always "setPropertyName:".

    I think you have the general idea, but might be getting hung up on dot syntax vs. bracket syntax.

    So if you were using bracket syntax, getting and setting the value would look like this:
    NSUInteger row = [self currentRow];
    [self setCurrentRow: 5];
    

    Using dot syntax, the exact same thing looks like this:
    NSUInteger row = self.currentRow;
    self.currentRow = 5;
    

    This is another reason I don't like dot syntax. Assigning and retrieving the value look exactly the same, so you have to pay attention to context - for example, left side of = instead of right side - to know what is going on. The "set" verbiage does not appear in dot syntax, though it is functionally equivalent.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • MikeTheCatMikeTheCat Posts: 24Registered Users
    edited April 2010
    Ahhh, [self SetCurrentRow:0];

    Of course, that follows from the rules. Duh! It just looks a little different because it's not self.something setBlah:

    I'll get used to it. Thanks again.
  • HackHack San FranciscoPosts: 2,137Registered Users @ @ @ @
    edited June 2010
    Thanks for the great refresher Brian
  • teekteek Posts: 49Registered Users
    edited June 2010
    Cool, I've read books on iPhone programming and I can't say I've seen this mentioned in any of the books I've read.. or maybe I simply didn't pay attention to it.
    Either way I have a s**tload of cleaning up to do because I've written thousands of lines of code THE WRONG WAY.

    On the bright side, my app will work even better when I'm done cleaning up direct instance variable access! :D
    ./t<br />
    <br />
    Mac Mini 2,26GHz - 4 GB<br />
    iPhone 3GS - 32 GB :: iPod Touch - 16 GB :: iPod Shuffle - 4 GB
  • intomointomo Posts: 62Registered Users
    edited June 2010
    Thanks for the great tutorial. This was really helpful.

    I have a property that is an integer. It gives me a warning if I try to release the instance variable. The warning is "invalid receiver type "NSInteger". What am I doing wrong? Many thanks for the thread. Everything else I've started doing because of the thread has worked great.
    @interface MultiPageViewController : UIViewController &lt;UIScrollViewDelegate&gt; {
    
    	NSInteger _limit;
    	
    }
    
    @property (nonatomic, readwrite) NSInteger limit;
    @end
    
    And in my .m
    
    #import &quot;MultiPageViewController.h&quot;
    
    
    
    
    @implementation MultiPageViewController
    @synthesize limit = _limit;
    
    // ...
    
    - (void)dealloc {
    	[_limit release], _limit = nil;
        [super dealloc];
    }
    
    
    @end
    
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited June 2010
    Retain/release only applies to objects. NSInteger is not an object.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • intomointomo Posts: 62Registered Users
    edited June 2010
    Duly noted. Thanks.
  • DanielMediaDanielMedia Posts: 71Registered Users
    edited July 2010
    This was an excellent guide. And looking back on some code I had written, I'm actually a bit confused now on how this piece of code works in one of my old apps if there is no instance variable to hold the value set by the getter/setter?
    // MyController.h
    
    #import &lt;UIKit/UIKit.h&gt;
    
    @interface MyController : UIViewController &lt;UITableViewDelegate&gt; {
    	// No instance variable here, but still works?
    }
    
    @property (nonatomic, retain) IBOutlet UITableView *tableView;
    
    @end
    
    // MyController.m
    
    #import &quot;MyController.h&quot;
    
    @implementation MyController
    
    @synthesize tableView;
    
    - (void)dealloc {
    	[super dealloc];
    }
    
    @end
    

    I was also unsure about primitive instance variables like ints, floats, doubles, BOOLS, etc. So these never have to be released? How does the memory management work with primitives? The value is set and just gets released automatically at some point?

    This was a fantastic guide btw... Much better than my books.
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited July 2010
    Implied instance variables. I haven't really read up on them. I believe it became available in the 64-bit runtime on the Mac, and has been possible on the iPhone the entire time. I don't believe it worked it the simulator until the 4.0 SDK, so I didn't care that much. I tend to use custom getters, and I haven't figured out how to do custom getters with implied instance variables, so it isn't something I've pursued with much vigor.

    Memory management does not apply to primitives.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • DanielMediaDanielMedia Posts: 71Registered Users
    edited July 2010
    Thanks for the info Slick. Appreciate it...
  • rickretsrickrets Posts: 198Registered Users
    edited July 2010
    Hey slick, thanks for this nice tutorial, it helped me a lot already :)
    I'm just not yet fully understanding it, just started on memory management..

    I can't figure this out, if you have the time could you help me please..

    I have this as viewDidLoad:
    - (void)viewDidLoad {
    	CLLocationCoordinate2D pubLocation = mapView.userLocation.coordinate;
    	
    	pubLocation.latitude = 52.22082;
    	pubLocation.longitude = 6.896361;
    	pubTitle = @&quot;Cafe De Pimpelaar&quot;;
    	pubSubtitle = @&quot;Elke woensdag een pubquiz!&quot;;
    	
    	placeMark *placemark = [[placeMark alloc] initWithCoordinate:pubLocation title:pubTitle subtitle:pubSubtitle];
    	[mapView addAnnotation:placemark];
    	
    	placemark = nil;
    	
    	NSLog(@&quot;Placemark: %i&quot;, [placeMark retainCount]);
    }
    

    the log is telling me that placeMark is -1, how can I get it to be 0?

    The line 'placemark = nil', is correct right? I know it's different then the placeMark (with a capital M), I logged placemark before, returning 2 or something, now it's just 0.

    Here is the code in placeMark.h:
    #import &lt;Foundation/Foundation.h&gt;
    #import &lt;MapKit/MapKit.h&gt;
    
    @interface placeMark : NSObject &lt;MKAnnotation&gt; {
    	CLLocationCoordinate2D coordinate;
    	NSString *subtitle;
    	NSString *title;
    }
    
    @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
    - (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate title:(NSString *)markTitle subtitle:(NSString *)markSubTitle;
    
    @property (nonatomic, retain) NSString *subtitle;
    @property (nonatomic, retain) NSString *title;
    
    @end
    

    And this is in placeMark.m:
    #import &quot;placeMark.h&quot;
    
    @implementation placeMark
    
    @synthesize coordinate, title, subtitle;
    
    - (id)initWithCoordinate:(CLLocationCoordinate2D) c {
    	coordinate = c;
    	return self;
    }
    
    - (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)markTitle subtitle:(NSString *)markSubtitle {
    	if (self = [super init]) {
    		coordinate = c;
    		title = markTitle;
    		subtitle = markSubtitle;
    	}
    	return self;
    }
    
    @end
    

    In case it is in there, any help or direction is greatly appreciated....

    regards,

    Rick
  • BrianSlickBrianSlick Treadmill Desk Ninja Posts: 10,689Tutorial Authors, Registered Users @ @ @ @ @ @ @ @
    edited July 2010
    placeMark *placemark = [[placeMark alloc] initWithCoordinate:pubLocation title:pubTitle subtitle:pubSubtitle];
    [mapView addAnnotation:placemark];
    	
    placemark = nil;
    	
    NSLog(@&quot;Placemark: %i&quot;, [placeMark retainCount]);
    

    1. Remember the 3-line pattern that was referenced earlier. Build it, do something with it, get rid of it. You do have 3 lines, but your 3rd one is incorrect. You did an alloc, you are supposed to release. By going straight to nil, you are not releasing, thus you are leaking the object.

    2. retainCount is not a reliable tool, for a number of reasons. For one, you have no idea what Apple's classes do behind the scenes. Let's say you add the object to an array, and then the retainCount becomes 200. Is that a problem? No idea. That could be 100% normal. But you have to trust Apple's classes to clean up after themselves.

    Additionally, you are asking the wrong thing for retainCount. You are asking the class for the retainCount, not a particular instance. I'm a little surprised this works at all, but it is a nonsense question if you think about it. This would be like asking NSArray for a retainCount. You don't want to ask the class, you want to ask the specific myParticularObject variable. And as a side note, follow proper naming convention. Class names should begin with a capital letter.

    Now let's pretend that you had done this entire block of code here correctly. You created it, you added it to the map, and then you released it and nil'ed out your variable. And then you ask the instance for a retainCount. But the variable is nil. So you are asking for the retainCount of nil. That is a meaningless question.

    Bottom line: retainCount is not a reliable method. Don't use it.
    - (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)markTitle subtitle:(NSString *)markSubtitle {
       if (self = [super init]) {
          coordinate = c;
    [B]      title = markTitle;
          subtitle = markSubtitle;[/B]
       }
    return self;
    }
    

    As noted previously, the use of instance variables in init methods is fine, and arguably preferred. But that doesn't free you from following the necessary memory management steps.

    Your strings are defined as retain properties. As mentioned already, if you do not use the @property's setter, then you are not participating in the memory management actions that it performs. So these string values are being assigned without a retain happening. This leaves you with several issues:

    1. Since the objects are not retained, they could die at any time.
    2. If you use the setter correctly later, then keep in mind what it does. It releases the old value and retains the new one. The old value would be the object you have assigned here. So you are releasing it, but that release is not balancing a retain. This means you are over-releasing it, which means your program will crash.
    3. You don't show it in your code, but you should have a dealloc method in your class, and you should be releasing all retain and copy properties there. So even if you never change the value, those strings will/should be released in dealloc, which will again be over-releasing, and you'll crash.

    So you'll have to take matters into your own hands and do some manual memory management, like so:
    title = [markTitle retain];
    subtitle = [markSubtitle retain];
    

    Now you are performing the same action that would happen if you were using the setter. The objects remain alive, and any releases that would happen later are now balanced.
    Professional iOS App Development. Available for hire.
    BriTer Ideas LLC - WWW | Facebook | Twitter | LinkedIn

    BTIKit | BTICoreDataKit | SlickShopper 2 | Leave a PayPal donation
  • rickretsrickrets Posts: 198Registered Users
    edited July 2010
    Thanks a lot, I'll read that a couple times tonight so it's printed in my head, also I will read this topic over and over again untill i fully, clearly understand it :)

    *you received a donation on paypal :)
Sign In or Register to comment.