attempt to mutate immutable object randomly thrown - iphone

One part of the program takes text from a uitextfield, copies it to a mutable string and then performs
sharedManager.ce_name=name.text
[sharedManager.ce_name replaceOccurrencesOfString:#" " withString:#"%20"
options:NSLiteralSearch range:NSMakeRange(0, [sharedManager.ce_name length])];
At this point it always gave me "attempt to mutate immutable object" - it was not random
The first time I got this error I changed it to
sharedManager.ce_name=(NSMutableString *)name.text
This STILL gave me the attempt to mutate immutable object error, but it would occur randomly - weird right?
I then changed it to
NSMutableString *mutable_name = [NSMutableString stringWithString:name.text];
sharedManager.ce_name=mutable_name;
It has yet to fail on me doing it this way but I am convinced that I have not found the solution.
my questions:
1) Could that fact that it was doing it randomly after the first fix indicate I have some deep seated memory management problem?
2) Why didn't the C-style cast fix it?
3) Will my current fix work?
Thanks for your time :)

The problem here is the way in which you're using casting. When you cast a pointer, it just starts treating the memory at that location as though it were a block of data representing that type.
So if I've got a pointer to a Car class: Car* mycar;, and I cast it to a Person object: (Person*)mycar;, the program will try to access the memory there as though it was pointing at a Person object. However, a car is not a person, except in an old TV sitcom, so when it tries to access members on this or call functions, it's going to try to go to a memory location that contains something other than what it's expecting, and undefined things happen (generally, crashing).
NSMutableString and NSString are incompatible in this regard, and so casting from one to the other will result in terrible times. Your fix ([NSMutableString stringWithString:]) is the correct solution.

If it was doing it randomly, it means that name.text was sometimes a mutable string and some times an immutable string.
Casting between objects like that doesn't change the class of the object. It won't make your immutable object mutable.
That "fix" is probably the best way to do it (at least from what I can see in the code you are showing)

Without seeing at least the declarations of the variables involved, it's difficult to say for certain, but your final solution, creating a new mutable string is likely the correct fix. As for your questions,
Not memory management per se, but it was probably overwriting something it shouldn't have somewhere.
Casts cannot change the fundamental type of an object. You had (presumably) an NSString and all the casting in the world cannot make it into an NSMutableString.
Like I said, probably, but we'd need to see more code to make sure. It's certainly a much better fix.

Related

Directly use of NSString

I find I usually directly use a NSString like:
self.text = #"word";
label.text = #"word";
function(#"word");
I think it is a wrong way to directly use NSString, because the #"word" will have a retainCount of 2 after it has been used. Is that right?
What is exactly the retainCount of #"" ? Is it an autorelease object or has a retain of 1?
What`s more, I encountered some memory leak as the pic shown below:
I suspect it is related to the direct use of the NSString.
Essentially, the retain count of NSString literals is infinite. The memory for these objects is reserved by the compiler at compile time and never gets released for the duration that your app is running, no matter how often you try to retain or release them.
This is another good example why it is wrong to care about retain counts. You should only care about the golden memory management rules: if you take ownership of an object (with alloc, new, copy or retain), you have to release or autorelease it later. Otherwise, you don't.
Quoting from String programming guide
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"/tmp/scratch";
Note that, when creating a string constant in this fashion, you should avoid using anything but 7-bit ASCII characters. Such an object is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated, though you can retain and release them as you do any other object.
the #"word" will have a retainCount of 2 after it has been used. Is that right?
No. This is a perfect illustration of why it is bad to think in terms of retain counts which are an internal implementation detail. You can think of string literals as strings that are "owned" by the executable image so they will not go away. You should treat them like any other Objective-C object.
If you do take a sneaky peek at the retain count of a string literal, you'll find it is set to some really big number (something like the maximum value for an NSInteger). This is treated as a special value by retain and release that they don't change.
The memory for string literals is allocated as part of the binary image at compile time. It can never go away. Your memory leak is not because of this.
No, it's a good thing to declare an autoreleased NSString by using directly #"". But NSString are retained in a particular way and it's not really possible to know what's being done at runtime. You may have weird retain count sometimes. Don't bother about your leak of 48 Bytes.... It's not related to your nsstring.

String compare vs Class compare in objective-C

I'm writing an objective-C game and I'm at the stage where i should start optimising some of my code in the game loops.
I have an extensive amount of class compare methods used,
if ([obj isMemberOfClass:[SomeClass class]])
etc.
I heard this sort of checking is quite expensive, because I choose only to have 1 array populated with multiple classes, I need some sort of class check.
I was thinking perhaps that adding a property to NSObject subclassing NSObject to contain a string property, that during initialisation i would make equal to the class name of that particular subclass. Then simply doing a
if ([obj.klass isEqualTo:#"SomeClass"])
Would this be beneficial?
I'm trying to keep as much dynamic coding out of the game loops as possible.
Thanks!
Short answer: no. String comparison is prohibitively more expensive compared to other methods of comparing (or: classifying, categorizing) objects.
Long answer: don't optimize what you haven't analyzed, measured and compared. What you really want to do before you start optimizing is to get a clear picture of how your app behaves and what its performance bottlenecks are. The change you're attempting is unlikely to lead to any noticeable change in performance, so I suggest to first find the real bottlenecks.
In this particular case, sending isEqual to an NSString is 4 times slower than isMemberOfClass if the test fails. And such conditional tests fail most of the time, which is why you should ignore the results of the test succeeding.
The successful string comparison is fast because it's a simple pointer comparison, if two strings are equal it is likely that they point to the same memory address. If they're not equal, then each character in the string will be compared for equality, probably by using the hash method.
Here are the results of the Object Comparison tests that I added to my performance test project. You can use that project to make further tests.
This is not really a direct answer to your question but is an answer in a broader sense.
In Objective-C the philosophy is more like that of Smalltalk in which you send the message and let the object decide what to do with it. If you find yourself having to do lots of tests to see what class an object is, you need to rethink your design.
For instance, if you have an array of objects and you want to convert each one to an integer to do some maths on it, you can do something like this:
for (id anObj in array)
{
int anInt = [anObj intValue];
// do something with anInt
}
It doesn't matter what the class of each anObj is, you can send -intValue to it. If your array is full of NSStrings and NSNumbers, for example, it doesn't matter, the code above will do what you expect.
Many classes do not define a method for the selector -intValue. For example, if you send that message to an instance of NSData it will respond by throwing an exception. There are a couple of ways to resolve this depending on circumstances.
ignore objects that don't respond to the selector by testing to see if the object knows about the selector
for (id anObj in array)
{
if ([anObject respondsToSelector: #selector(intValue)])
{
int anInt = [anObj intValue];
// do something with anInt
}
}
Define the selector for all classes you know will be put in the array. This is done by declaring a category. This way you can extend any Objective-C class without subclassing. For instance, you can define an intValue method for NSData that returns its length, or the sum of its bytes or some other appropriate value.
Formalise the requirement by declaring a protocol. You can then test for conformance to the protocol, or rely on compile time checks to make sure the objects you put in the array conform to the protocol.
There are lots of things you can do, but you need to get away a bit from the C++/Java model of class hierarchies. Objective-C is much more flexible in that respect.

Passing a pointer that is part of an object (Cocoa)

OK, I have a custom object (an NSManagedObject subclass, if it matters) and I want to pass a pointer to one of its iVars to a function that I've set up to modify such values. With a normal pointer you'd just prefix it with an ampersand (&) as in the classic NSError &error example, but that can't be done with dot notation. I can't just pass &object.iVar as I'd hoped. Can anyone suggest a simple and elegant way to obtain the pointer of iVar so that I can pass it? I am loath to pass the entire object for reasons of code structure and neatness.
-Ash
Argh, as is almost always the case, I ask a question after an hour of frustrating puzzling then ten minutes later answer it myself. I don't know, maybe asking questions is some kind of therapeutic trigger for answers... shame this isn't a psychology website.
Anyway, my solution was to add a new 'pseudo-getter' method to the object I'm trying to access the pointer from that looks a bit like this:
- (Pointer **)getIVarPointer
{
return &iVar;
}
It's a bit cludgy, but since I only have that one iVar whose pointer I need to obtain it's not too bad. On ther other hand if there is a simpler, more 'official' way of doing this, I'd love to know it!

NSString vs NSMutableString with stringByAppendingString

So, I'm fairly certain that if I plan on manipulating strings often, such as with stringByAppendingString, I should be using variables of type NSMutableString.
But what if I'm doing something like this?
UILabel *someLabel = [[UILabel alloc] init];
[someLabel setText: [[someDictionary objectForKey:#"some_key"] stringByAppendingString:#"some other string"];
I read that if you use stringByAppendingString on an NSString, you end up with leaks because the pointer associated with the initial NSString moves around, pointing to the new string created by the append, whereas with NSMutableString, your pointer always points to that mutable string.
So my question is, what is implicitly happening when I call stringByAppendingString on something that is a string, but not explicitly an NSString or an NSMutableString? Such as, in my above case, the value of some key in a dictionary. Is doing this wrong, and should I be doing something like below?
[[[NSMutableString stringWithString:[someDictionary objectForKey:#"some_key"]] stringByAppendingString:#"some other string"]]
I read that if you use
stringByAppendingString on an
NSString, you end up with leaks
because the pointer associated with
the initial NSString moves around,
pointing to the new string created by
the append, whereas with
NSMutableString, your pointer always
points to that mutable string.
That sounds like the advice of someone who didn't quite have a grasp of what is going on with the memory management. Sure, [NSString stringByAppendingString] returns a new string. But what you do with that new string is up to you. You could certainly cause a memory leak by reassigning the result to a retained property in a careless fashion, like so:
myStringProperty = [myStringProperty stringByAppendingString:#" more bits"];
The correct form would be to use self, like so:
self.myStringProperty = [myStringProperty stringByAppendingString:#" more bits"];
Follow the cocoa memory guidelines.
As for dictionaries and other collection types: treat what comes out of the dictionary appropriately given the type you know it to be. If you pull an object out which is actually an NSString, but try to use it as a NSMutableString, your app will fall over (with 'selector not found' or similar). So in that case, you do need to make a new NSMutableString from the NSString.
Interesting note: Apple chose to make NSMutableString a subclass of NSString. Something about that seems unwise to me -- if something looks to be immutable, because it has type NSString, I want it to be immutable! (But in fact it could be NSMutableString.) Compare that to Java, which has a String class and a completely separate BufferedString class.
I've always been a fan of [NSString stringWithFormat#"%#%#", a, b]; because then you clearly get a new autoreleased string and can dispose of "a" and "b" correctly.
With [someDictionary objectForKey:#"some_key"], you will be getting the type of object that was put into that dictionary originally. So blindly calling stringByAppendingString without knowledge of what's in that dictionary seems like a bad idea.
-stringByAppendingString is going to return you a new NSString that is distinct from both strings involved. In other words:
NSString *string3 = [string1 stringByAppendingString:string2];
string3 is an entirely new string. string1 isn't changed at all, nothing happens to its memory location or contents. The person who told you that probably just misunderstood what was going on.
[mutableString1 appendString:string2];
In this case, mutableString1 still points at the same object, but the contents of that object have been altered to include string2.
One last thing to keep in mind is that if you are using mutable strings, you should be careful with sharing references to it. If you pass your mutable string to some function which keeps a pointer to that mutable string and then your code changes that mutable string at some point in the future, the other reference is pointing at exactly the same object which means the other code will see the change as well. If that's what you want, great, but if not you must be careful.
One way to help avoid this problem is to declare your #property statements for NSStrings to be "copy" instead of "retain". That will make a copy of your mutable string before setting it in your property and the -copy method implicitly gives you a NON-mutable version, so it'll create an NSString copy of your NSMutableString.
If you follow the rules for memory management, you will be fine using stringByAppendingString. In a nutshell:
if you own an object, you need to release or autorelease it at some point.
you own an object if you use an alloc, new, or copy method to create it, or if you retain it.
Make sure you read up on Apple's Memory Management Rules.
In the first code sample in your question, you aren't using alloc, new, copy or retain on any of the NSStrings involved, so you don't need to do anything to release it. If outside of the code that you've included in the sample you are using alloc, new, copy or retain on any NSStrings, you would need to ensure that they are released later.

Couldn't I just pass an copied string to an Core Data property?

The docs say:
The default implementation does not
copy attribute values. If the
attribute value may be mutable and
implements the NSCopying protocol (as
is the case with NSString, for
example), you can copy the value in a
custom accessor to help preserve
encapsulation (for example, in the
case where an instance of
NSMutableString is passed as a value).
So instead of getting into trouble and inconvenience with overwriting accessors in my NSManagedObject subclass, couldn't I simply do something like this?
myManagedObject.firstName = [[firstNameMutableStr copy] autorelease];
This would have the exact same effect, or not? The dynamic implementation would retain that anyways ... so.... why not the easy way?
It's an open question whether having to remember to copy the mutable string every where in code you set the attribute is "the easy way."
With a custom accessor, you just write the copy once then forget about. It copies automatically from that point on.
Just imagine that in thousands of lines of code you forgot to copy just once and developed a subtle bug because that one attribute of the managed object sporadically changed because some other totally unrelated code subsequently changed the mutable string you held only by reference.
I could tell you some stories of weekends lost to debugging because someone took "the easy way."