Re: Best Way to Handle Properties?
Re: Best Way to Handle Properties?
- Subject: Re: Best Way to Handle Properties?
- From: Dave <email@hidden>
- Date: Wed, 20 Aug 2008 14:59:45 +0100
On 20 Aug 2008, at 13:30, Ken Thomases wrote:
On Aug 20, 2008, at 6:05 AM, Dave wrote:
This makes memory management awkward. This code is creating an
object using alloc, so it's responsible for releasing it.
However, you're not keeping a pointer to the new string you've
created. You're just passing it to the PersonDetails object and
then forgetting it. So, you can't release it.
Yes, this is what worried me. The set method (setFirstName) stores
the NSString pointer inside itself, and the "reset" method
releases it in this case. The reason I did this is because if I
were to specify "copy" instead "assign" for the property, then
there would be two NSString Objects allocated one here and one
inside the "set" method. I was trying to avoid allocating two
Objects, e.g. the method would look something like this:
-(void) setFirstName:(NSString*)theNewValue
{
if (FirstName != theNewValue)
FirstName = [theNewValue copy];
}
Or am I missing something?
You're engaging in premature optimization. Get it right first,
then worry about performance (after measuring!).
I just took the example from the Objective C manual.
You also overlooked the option to have the property use "retain".
Please review the memory management guidelines and conventions.
The code you presented created an object, so it's responsible for
making sure it's released. The PersonDetails class has its own
separate responsibilities. It must ensure that its properties
stick around for as long as it needs them, so it should either
retain or copy anything passed into it because it doesn't have any
other way of being sure about such objects' lifetimes. Naturally,
whatever it retains or copies it then has the responsibility to
release.
The setter you wrote just above is wrong because it fails to
release whatever might have been in the FirstName ivar when it was
invoked. Thus, it will leak. Apple provides several possible
forms that accessors typically take in their documentation. Unless
you have a good reason to deviate, you should follow those
guidelines. Even better, allow the compiler to synthesize
accessors whenever possible.
Ok, I was totally confused about retain and assign.
Third, you can use a convenience method which creates a string
for you but doesn't leave you responsible for releasing it, such
as +stringWithCharacters:length:.
What is the difference between -stringWithCharacters:length: and
+stringWithCharacters:length: ? Looking at the documentation it's
not obvious (to me anyway) what the difference is.
Well, the former doesn't exist. ;)
A plus at the beginning of a method name indicates that it's a
class method. A minus means it's an instance method.
Also, +stringWithCharacters:length: is a convenience constructor.
That is, it returns to you a new object but one that you're not
responsible for releasing because, technically, you're code didn't
create it; the convenience constructor created it, so that code has
the responsibility for arranging that it will eventually be
released. You said earlier that you had read about memory
management. I think you need to review the memory management
guide. This subject is one that most people need to read about
several times before it really "clicks".
So, I guess the best way to do it would be to Allocate and Free a
new "PersonDetails" object each time through the loop
That will work, although you don't "free" objects, you release them
and they decide when it's time to deallocate themselves (because no
other strong references to them remain; i.e. their retain count
reaches zero).
, or have the "ReadPersonString" method allocate and return a
"PersonDetails" object. The "Reader" Object could then keep track
of the "PersonDetails" object and free it on subsequent calls to
"ReadPersonString" and when the file is closed.
If you go that route, then the reader should autorelease the
PersonDetails objects it returns. I wouldn't recommend a scheme
where the reader keeps track of the objects it has returned to free
them later. That's what autorelease pools are for.
Firstly in the real code there is a "PersonDataValid" flag so I
can tell if it's a good "Person" or not, secondly, unless I put a
whole load of logic in the "PersonDetails" object and/or have it
know about all the reader objects, it can't initialize a "salient"
object. Or do you mean something else?
I mean the initializer method should take as arguments all of the
pieces of information required for a Person (or PersonDetails)
object to be valid. Generally, if an object exists (is
successfully allocated and initialized), it should be valid. If it
can't be made valid, then the initializer should fail (return
nil). If there are different possible combinations of information
that could make a valid Person, then that suggests you want to have
several different initializers, each taking different sets of
arguments. If you do, please make sure you understand the notion
of designated initializer and how all of your other initializers
should funnel through that one.
The problem with that there are a *LOT* of properties which is why
the data was being passed in a structure and now being stored in an
object. The initializer would have about 56 arguments, which in my
book is horrible. This is a chicken and egg situation, I need to read
around 56 pieces of information and store them in a "Common" format.
I could use a C Structure but then I'd still have the problem of de-
allocating/freeing/releasing all the NSStrings.
So, I allocate and initialize a "NULL" object and then populate it
when I've read the data (from whatever source).
In some cases, it makes sense to design an initializer that takes a
_source_ of information. In that case, the initializer knows how
to extract the information it needs from the source. As you
worried, a bad design of this type might require the class to know
intimate details of several such sources of information, resulting
in close coupling between classes and violations of encapsulation.
However, it's possible to make a fairly general design of this
type. In particular, Cocoa already has one: the NSCoder/NSCoding
mechanism. You might consider using this approach for your
design. See the Archives and Serializations Programming Guide for
Cocoa.
The file format is complex and the sources of data are quite
different, to design and implement a "common" information source from
with the object that holds the data would be very complex and
overkill in this case in my opinion.
When you're done with a given Person object, you release it. If
you need a new one, you allocate and initialize a new one.
Ok, I think this is covered above. One more question. If I were to
release a "PersonDetails" object, would the NSString's be
released? If not, do I have to implement my own release method?
Since you should make the PersonDetails object own its properites,
it should have the responsibility for releasing them when it's
deallocated. You achieve this by implementing a -dealloc method on
the class. Again, see the memory management guide.
Thanks again,
All the Best
Dave
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden