Re: Re Re: String variables in classes
Re: Re Re: String variables in classes
- Subject: Re: Re Re: String variables in classes
- From: "Stephen J. Butler" <email@hidden>
- Date: Sun, 2 Jan 2011 18:10:36 -0600
On Sun, Jan 2, 2011 at 5:17 PM, Brian Durocher <email@hidden> wrote:
> #import <Foundation/Foundation.h>
>
> @interface Calculator : NSObject
> {
> double accumulator;
> NSString* caption;
> NSString* name;
> NSString* temp;
> }
>
> - (id) init;
> - (void) setAccumulator:(double) n;
> - (void) printAccumulator;
>
> - (NSString*) caption;
> - (NSString*) name;
> - (NSString*) temp;
>
> - (void) setCaption: (NSString*)input;
> - (void) setName: (NSString*)input;
> - (void) setTempString: (NSString*)input;
You violate the KVC pattern here. Your getter is "temp" but your
setter is "setTempString". Either make the getter "tempString" or the
setter "setTemp:".
> - (void) combineString: (NSString*) input1 : (NSString*) input2;
>
> - (void) printCaption;
> - (void) printName;
> - (void) printTemp;
>
>
> @end
>
> @implementation Calculator
>
> - (id) init
> {
> if ( self = [super init] )
> {
> [self setAccumulator:0];
> [self setCaption:@"Default Caption"];
> [self setName:@"Default Name"];
> [self setTempString:@"empty"];
Most Cocoa conventions say to just set the instance variables directly
inside your init* functions. There's nothing wrong with doing it this
way, per se, but most people will just do this:
accumulator = 0;
caption = @"Default Caption";
name = @"Default Name";
temp = @"empty";
> }
> return self;
> }
>
> - (void) setAccumulator: (double) n
> {
> accumulator = n;
> }
>
> - (void) printAccumulator
> {
> NSLog(@"Accumulator = %f", accumulator);
> }
>
> - (NSString*) caption {
> return caption;
> }
>
> - (NSString*) name {
> return name;
> }
>
> - (NSString*) temp {
> return temp;
> }
>
> - (void) setCaption: (NSString*)input
> {
> [caption autorelease];
> caption = [input retain];
> }
>
> - (void) setName: (NSString*)input
> {
> [name autorelease];
> name = [input retain];
> }
>
> - (void) setTempString: (NSString*)input
> {
> [temp autorelease];
> temp = [input retain];
> }
>
> - (void) combineString: (NSString*) input1 : (NSString*) input2
> {
> [temp autorelease];
> temp = @"";
> temp = [[temp stringByAppendingFormat:@" %@ %@ \n", input1, input2]
> retain];
> }
- Charles asks 'why the @""' and I can answer that question: because
you couldn't figure out another way to call stringByAppendingFormat:
could you? The answer is that in this case you should be calling
+[NSString stringWithFormat:]. However...
- You really should be using your mutator here. I know it's an
advanced topic at this point, but KVC and KVO will be much easier
later if you don't go setting your instance variable willy-nilly. How
about this:
- (void) combineString: (NSString*) input1 : (NSString*) input2
{
[self setTempString:[NSString stringWithFormat:@" %@ %@ \n", input1, input2]];
}
But going back to your original question, and guessing what this code
is really supposed to do as opposed to what it actually does...
I used to do a bit of C++ programming and I think here's the rub. In
STL the std::string is mutable. So if you do:
std::string str1;
str1 = "foo\n";
str1 += "bar\n";
Then str1 is changed, you don't need to store the return value of
operator+=. But in Cocoa NSString is not mutable. So if you do:
NSString *str1, *str2;
str1 = @"foo\n";
str2 = [str1 stringByAppendingString:@"bar\n"];
Then str1 and str2 POINT TO DIFFERENT OBJECT INSTANCES! str1 still
equals "foo\n" and str2 equals "foo\nbar\n". See where the method name
begins with "stringBy"? That "string" means it is returning a new
instance of NSString.
Which brings us to what NSMutableString does. Consider this code
instead (noting that I call [NSMutableString stringWithString because
@"" are always immutable):
NSMutableString *str1, *str2;
str1 = [NSMutableString stringWithString:@"foo\n"];
str2 = [str1 stringByAppendingString:@"bar\n"];
What do you suppose happens? Exactly what happened before. In fact,
str2 isn't a mutable string at all, it is immutable (because
stringByAppendingString: is declared in the base class and returns an
immutable instance). In fact, when you compile you get a warning on
that third line.
If you really want to mutate str1 like you would in C++ std::string
take a look at the documentation for NSMutableString. I don't know why
you didn't start there in the first place, there's only a dozen or so
methods it adds on top of the base class. Two you might like are
appendString: and appendFormat:.
NSMutableString *str1;
str1 = [NSMutableString stringWithString:@"foo\n"];
[str1 appendString:@"bar\n"];
> - (void) printCaption
> {
> NSLog(@"%@ \n", self.caption);
> }
> - (void) printName;
> {
> NSLog(@"%@ \n", self.name);
> }
> - (void) printTemp;
> {
> NSLog(@"%@ \n", self.temp);
> }
There's nothing wrong with all these print methods, but they are a
little unCocoa like. The Cocoa way to do this is to override the
description method and return all the info about your object. In fact,
these two lines are more or less the same:
NSLog( @"object = %@", myObject );
NSLog( @"object = %@", [myObject description] );
And yes, you're missing a dealloc. How did you plan on balancing all
those retains you did on instance variables?
> @end
>
>
> int main (int argc, const char * argv[]) {
> NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>
> // insert code here...
>
> Calculator *theDevice = [[Calculator alloc] init];
>
> [theDevice init];
> [theDevice printAccumulator];
> [theDevice setAccumulator:10];
> [theDevice printAccumulator];
> [theDevice setName: @"Brian D"];
> [theDevice setCaption: @"Rocks"];
>
> [theDevice combineString:[theDevice name] : [theDevice caption]];
>
> [theDevice printTemp];
> [theDevice printName];
> [theDevice printCaption];
>
>
> NSLog(@"The two variables: %@, %@ \n", [theDevice name], [theDevice
> caption]);
> NSLog(@"Hello, World!");
> [theDevice release];
>
> [pool drain];
> return 0;
> }
>
> </code>
>
>
> _______________________________________________
>
> 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
>
_______________________________________________
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