Do NSMutableAttributedString addAttribute methods retain the passed in value? - iphone

For example is the following code memory safe?
NSMutableAttributedString *str = ...;
CTFontRef aFont = CTFontCreateWithName((CFStringRef)fontName, size, NULL);
[str addAttribute:(NSString*)kCTFontAttributeName value:(id)aFont range:range];
CFRelease(aFont);
Also, is CTFontCreateWithName efficient to call multiple times or should some effort be made to cache CTFontRef's for the same font/size?

I believe it is safe to release the font object after adding it as an attribute. I have done so in my own Core Text code and never have any issues.
As for caching, it would make sense to keep a font object around if it will be used multiple times rather than releasing it and recreating it many times. Though, this is likely pre-optimisation, so I wouldn't make any conscious effort just yet. Profile it with your current code and decide whether or not the extra microseconds will be worth the work.

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.

How can I keep memory usage low with a lot of NSStrings, or how do I release NSStrings?

I am working on an app that imports a (very) large csv file into Core Data for catching purposes. The process goes something like this:
Parse the file line-by-line into an NSMutableArray full of NSStrings
After X number of lines, import the array into Core Data (this involves manipulating and in some cases creating new NSStrings)
[NSMutableArray removeAllObjects];
Rinse and repeat
At first glance it looks like the memory should be freed up at the conclusion of each cycle. With large files, however, I am finding that the app crashes after signaling a couple low memory warnings. Running the leaks tool tells me that most of the memory is being used up by CFString objects, which I understand are related to NSString objects (although I don't know how)
I understand that NSString are reused whenever possible, and that they don't act quite the same as other objects where memory is concerned, although I don't understand any of the details. How can I reclaim the memory that my NSString objects are using?
Running the leaks tool tells me that most of the memory is being used up by CFString objects, which I understand are related to NSString objects (although I don't know how)
NSString is actually a class cluster. Although you think you are working with NSStrings, you are almost certainly really working with one of its subclasses. The Cocoa framework chooses which subclass to use depending on circumstances.
CFString is actually not really an NSString at all, it is the pure C string object used by Core Foundation. However, you'll find it is "toll free bridged" to NSString. This means that, to Cocoa, it looks like an NSString. The reason you are seeing lots of CFString usage is because whatever Cocoa API you are using to obtain these strings ultimately performs its work in Core Foundation.
Anyway, all that is irrelevant to your problem except for the fact, that lots of CFStrings more or less means the same as lots of NSStrings. What you need to reduce your memory footprint is nested autorelease pools as Girish has already said. As a first step, modify your algorithm like this:
Create a new autorelease pool.
Parse the file line-by-line into an NSMutableArray full of NSStrings
After X number of lines, import the array into Core Data (this involves manipulating and in some cases creating new NSStrings)
[NSMutableArray removeAllObjects];
drain the autorelease pool
Rinse and repeat (start at 0)
If this doesn't help, or only helps a bit, consider bracketing just the parsing with an autorelease pool.
I am assuming that you don't have memory leak.
If you are using too much autoreleased object this can happen
You try following
Create nested auto release pools --- some time happen that you have some long running loops where auto release object get accumulated. -- so add custom auto release pool to release the auto release object when you required.
Don't use autorelease object in the parsing cycle --- do manual object allocation and release once your work is done.
You can't sure that the memory is consumed by NSStrings only. I suggest you check it thoroughly. Try to go for "Build and Analyze" it will help you to find out leaks.
While using NSString object, instead of going for autoreleased objects like
[NSString stringWithFormat#""];
create your own object and release it as soon as you done with it.
NSString * string = [[NSString alloc]initWithFormat:#""];
//use string object
[string release];
this way you can be sure, that you releasing the string there itself.
or create an Autorelease pool
NSAutoReleasePool * pool = [[NSAutoReleasePool alloc]init];
// do you coding, creation of objects, releasing them, whatever...
[pool drain]; or [pool release];
Also have a look at these memory management tips

UILabel changing during runtime, managing memory for changing strings

I have a couple labels I am using as a HUD for the player during a game. I am updating these labels frequently, so that the player has up-to-date information. The problem is is that I've been using
uiLabel.text = [NSString stringWithFormat:#"%3.0f", value];
to pass the new value that the label should have. I have noticed, however, that I have something of a soft-memory leak here. As I'm doing this update multiple times a second and this creates a string that is set to autorelease, I'm ending up taking more memory than I need. And keeping it, as the view is not going away.
I also tried to alloc and release strings explicitly, such as:
NSString* value = [[NSString alloc] initWithFormat: #"%3.0f", value];
uiLabel.text = value;
[value release];
However, I find that this seems to cause the same thing, but faster, though I don't know why. In this situation I would have thought there should never be strings sitting around waiting to be released at all, since I'm so explicitly dismissing them.
Can anyone see what I'm doing here that I obviously am failing to see? Is there a better/more preferred way to handle this? Some cursory searching didn't turn up much for me.
You're not doing anything out of the ordinary. Even with:
uiLabel.text = [NSString stringWithFormat:#"%3.0f", value];
the autorelease pool gets drained every time your code returns control to the run loop (so at least as often as you see the UI updating). If you see growing memory allocations, you should look elsewhere.

Most efficient way to manage formatted strings for constantly updated UIlabels in Xcode

I have a UILabel in an interactive calculator application that is continually being refreshed with a newly formatted message as the user changes a UISlider value. My question is what is the most efficient way to manage the strings:
NSString *data = [[NSString *alloc] initWithFormat:#"Value A: %0.1f, Value B: %0.1f, valueA,valueB];
myUILabel.text = data;
[data release];
or
[myMutableString setString:#""];
[myMutableString appendFormat:#"Value A: %0.1f, Value B: %0.1f, valueA,valueB];
myUILabel.text = myMutableString;
Any advice would be appreciated
Creating a single, non-mutable string (your first example) is going to be more efficient than creating and then modifying a mutable string.
However the real answer is that it doesn't matter. The amount of time is negligible in user interaction terms, and any temporary objects created as a side effect will be freed on every pass through the event loop anyway, so worrying about this at all is premature optimization.
As the string is there to be read by the user and so has to remain visible for a time I doubt that the speed of the format matters as it will take much less time than it takes for a user to read the value.

How else can I avoid leaking this Core Foundation object?

The following leaks:
CFStringRef labelName = ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(aMultiRef, indexPath.row));
cell.textLabel.text = (NSString *)labelName;
CFRelease(labelName);
Wondering if there a way to rewrite it so it doesn't leak without breaking out & assigning ABMultiValueCopyLabelAtIndex(aMultiRef, indexPath.row) to a CFStringRef that I then need to manually CFRelease 2 lines later? Of course, it's not a big deal to do just that...I'm just curious.
Edit: Would CFAutoRelease work? see my comment below
Because of Copy/Get semantics you are required to release anything that comes out of an API with Copy in it. ABMultiValueCopyLabelAtIndex meets that requirement, so unfortunately you'll need to acquire this reference and release it later on.
You can autorelease using Objective-C (so long as you have a pool in place). Just cast to id first. E.g. [(id)labelName autorelease] will work fine and it’s perfectly legal (because CFStringRef is and toll-free bridged with NSString). You can actually do this with any CoreFoundation based type, although I don’t believe Apple publicly document this so in theory, this could change.