No, foo is variable holding a pointer to an NSString. The assignment foo = @"bar" sets the value stored by the pointer foo to the address of the NSString @"bar". There is no copy made. If foo already pointed to an other NSString instance that was not a string constsant (i.e. like @"bar") and there are no other references to that instance, then you have a memory leak. You would
[foo release];
foo = @"bar";
in that case. You do not need to retain or release string constants like @"bar".
String constants cannot be mutated, so you will get a runtime error if you try to modify the value of a constant string. There's no difference between assigning @"bar" to an NSString* vs an NSMutableString*. Of course, you won't be able to use the mutating methods of the NSMutableString without a runtime error just because you assign the address of @"bar" (an NSString instance) to a variable of type NSMutableString*. If you want to mutate the string, you would do
NSMutableString *mutableFoo = [@"bar" mutableCopy];
In this case, a copy is obviously made and you are responsible for releasing mutableFoo when you're done with it.