UILabel changing during runtime, managing memory for changing strings - iphone

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.

Related

Table view data sources running twice, scope issue

I have a UITableView where numberOfSectionsInTableView and numberOfRowsInSection are being called twice, with scope issues on the second run. If I mask the problem, I get a scope issue on the first run of cellForRowAtIndexPath.
Most data all comes from an NSDictionary which is configured during viewDidLoad. I also have an NSArray configured at the same time. Once set they are never changed nor released.
When numberOfSectionsInTableView is called the first time, it's fine. Counts the elements as needed etc. It's then immediately called a second time (no idea why). On the second run, it cannot access the NSDictionary or NSArray items. Crash even when trying to NSLog them. For example:
NSLog(#"theMainDictionary %#",theMainDictionary);
usually results in EXC_BAD_ADDRESS but occasionally something like this:
theMainDictionary <_UITableViewSeparatorView: 0x4e73680; frame = (0 307; 320 1); opaque = NO; autoresize = W; layer = <CALayer: 0x4e4bf20>>
Again, this same line runs fine (logging the dictionary as expected) the first run through.
If I mask the problem by returning a fixed NSInteger, numberOfRowsInSection then does the same thing. If I mask numberOfRowsInSection, cellForRowAtIndexPath crashes on the first run. Same issue though - can't access theMainDictionary or the related NSArray.
I can't figure out why they're running twice - there's no reloadData anywhere. Nor do I know why the second call runs any differently. Any assistance greatly appreciated.
You're probably creating your dictionary with [NSDictionary dictionary] or one of the several similar factory methods (which returns an autoreleased instance), and then saving it directly to an ivar without retaining it. It will work fine until your program gets back to the main run loop, at which time the autorelease will resolve and the object gets freed.
There are a few ways to fix it:
Assign to a property declared retain rather than an ivar. This means self.theMainDictionary rather than just theMainDictionary. This will retain it for you, so it will stick around until you release it (or assign a different dictionary or nil to the property).
Use [[NSDictionary alloc] init] (or one of the many other init methods) rather than [NSDictionary dictionary] style. This returns an instance that you own, so it will stick around until you release it.
Explicitly call retain on the dictionary when saving it to the ivar. This takes ownership, so it will stick around until you release it.
In all cases, do remember to release the dictionary in your dealloc method, or the memory will leak.
All of the above probably applies to the array too. See Apple's documentation for a much more detailed explanation of memory management in Cocoa.

Memory leaks caused due to CoreFoundation Framework

I am developing an iPhone application which mainly makes use of the Address Book and database. After fetching about 3000 contacts from the address book, I am attaching string tags to the contacts (5 for each). I am saving my tags in the database.
For Load testing purpose i have added 10,000 tags to the App. But during the load testing of my application, I observed some memory leaks which were not related to the Application code but represents a set of Instruction sets. Also Instruments showed Foundation as the responsible library for the Leak (Extensive use of NSString,NSDictionary,NSArray which belongs to the Foundation framework). My application crashes after 10 - 15 mins of usage.The Crash report mentions, application crashed due to low memory.
Memory profiling using CLANG shows zero leaks. How do i solve these memory leaks?
Are these leaks the real culprit behind the crash? Are there any other tools available to check memory leaks?
I often find my leaks say they're caused by Core Foundation (or any other framework for that matter) but are really my own. With the exception of the Simulator, rarely will you find excessive leaking in the frameworks.
If you open up the detail panel to the right in Instruments you may find listed your App's methods in there. That will give you indication of where it could be coming from in your code. One leak can spring many other leaks, and you may have to find the top level culprit to get rid of the lower level ones.
You should not expect Clang to do anything but find the most obvious leaks. It's very handy, but that's it, just a helpful addition to compiling.
clang is not a leak checker. It only detects a small subset of issues.
For memory leak debugging you should focus on Instruments, specifically the Object Allocation and Leaks instruments. Be sure to understand the difference between leaks and other source of high memory usage though.
Once you've determined that objects are leaking, use Instruments to examine their allocation stack trace (so you can tell what object it is), and their retain/release history.
If it's not a leak, then I suggest investigating the instructions here:http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
Most likely you have code that is creating the foundation objects. Leaks shows you the place of allocation but that is generally due to a call your code made to create the object. You can look at the call chain in Instruments and go back along the call chain until you get to your code - that is the place where you are causing the allocation. Now, for that allocation, look at your memory handling for that object: Do you release it some time later?
There are lots of ways you can fail to release memory property so it would be hard to guess which one you might be hitting. Ones I see when helping people include allocating an object and assigning it to an instance variable via a property with the retain attribute, something like this:
#property (retain) NSString* myString;
...
self.myString = [[NSString alloc] initWithString: #"foo"];
the alloc+init creates a retained object, the self.myString = increments the retain count again. If coded correctly, the dealloc method releases the property via one of:
[myString release];
or
self.myString = nil;
And that takes care of the retain added with the self.myString = but does NOT take care of the retain from creation. Solutions, ONE of the following:
myString = [[NSString alloc] initWithString: #"foo"]; // doesn't call the setter method so no assignment retain - but doesn't call the setter which might be bad if non-trivial setter.
self.myString = [[[NSString alloc] initWithString: #"foo"] autorelease];
autorelease releases the alloc+init retain.
Now of course this is a contrived example because you'd probably really use:
self.myString = [NSString stringWithString: #"foo"];
which is a class method returning an autoreleased string and avoids the problem. But the idea is to show a simple example to explain this type of issue.
There are many other ways to not release memory properly, but the advice to work your way back up the call-chain until you get to your code is the way to go look at where you are triggering the allocation of the memory and then you can figure out why you aren't releasing that properly.
Try to do some issues in u code:
1. Please avoid hide declaration like
NSString *string = [dictionary valueForKey:[dictionary2 valueForKey:#"something"]]
Correct code is:
NSString *key = [dictionary2 valueForKey:#"something"];
NSString *string = [dictionary valueForKey:key];
key = nil;
Try to avoid declaration with autorelease and local declaration like:
NSArray *array = [NSArray array];
If u do this, make sure that u have:
NSArray *array = [NSArray array];
.... some code where array is using;
array = nil;
Better idea is alloc and release immediately when u don't need object and put it to nil.
3. Check if u using correct setters. Probably better idea is avoid to using it, at my experience, deallocate class start leaks for getters and setters, which was using before.
If u post some part of u code, where u seen most leaks (instruments give u possibility to click on leaked objects and see volume of leaks in programming code) community can suggest more.

Some stress tests on my Iphone app

I ran a few stress tests on my Iphone app. The results are below. I am wondering if I should be concerned and, if so, what I might do about it.
I set up a timer to fire once a second. Whenever the timer fired, the app requested some XML data from the server. When the data arrived, the app then parsed the data and redisplayed the affected table view.On several trials, the app averaged about 500 times through the loop before crashing.
I then removed the parsing and redisplay steps from the above loop. Now it could go about 800 times.
I set up a loop to repeatedly redisplay the table view, without downloading anything. As soon as one redisplay was completed, the next one began. After 2601 loops, the app crashed.
All of the above numbers are larger than what a user is likely to do.
Also, my app never lasts long at all when I try to run it on the device under instruments. So I can't get useful data that way. (But without instruments it lasts quite a while, as detailed above.)
I would say you need to be very concerned. The first rule of programming is that the user will never do what you expect.
Things to consider:
Accessor methods. Use them. Set up
properties for all attributes and
always access them with the
appropriate getter/setter methods:
.
object.property = some_other_object; -OR-
[object setProperty:some_other_object];
and
object = some_other_object.some_property;
object = [some_other_object some_property];
Resist the temptation to do things like:
property = some_other_object;
[property retain];
Do you get output from ObjectAlloc?
There are 4 tools from memory leaks,
performance and object allocations.
Are none of them loading?
What do you get when the app crashes?
EXEC_BAD_ACCESS or some other error?
Balanced retain (either alloc or
copy) and release. It is a good idea
to keep every alloc/copy balanced
with a release/autorelease in the
same method. If you use your
accessors ALL OF THE TIME, the need
for doing manual releases is seldom.
Autorelease will often hide a real
problem. It is possible Autorelease
can mask some tricky allocation
issues. Double check your use of
autorelease.
EDITED (Added based on your fault code)
Based on your above answer of "Program received signal: 0". This indicates that you have run out of memory. I would start by looking for instances that your code does something like:
myObject = [[MyClass alloc] init];
[someMutableArray addObject:myObject];
and you do not have the "release" when you put the new object into the array. If this array then gets released, the object, myObject, will become an orphan but hang around in memory anyway. The easy way to do this is to grep for all of your "alloc"/"copy" messages. Except under exceedingly rare conditions, there should be a paired "release""/autorelease" in the same function. More often than not, the above should be:
myObject = [[[MyClass alloc] init] autorelease];
[someMutableArray addObject:myObject];

Use autorelease before adding objects to a collection?

I have been looking through the questions asked on StackOverflow, but there are so many about memory management in Objective-C that I couldn't find the answer I was looking for.
The question is if it is ok (and recommnded) to call autorelease before adding a newly created object to a collection (like NSMutableArray)? Or should I release it explicitly after adding it. (I know NSMutableArray willl retain the object)
This illustrates my question:
Scenario A (autorelease):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
}
Scenario B (explicit release):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
}
I assume both are correct, but I am not sure, and I sure don't know what the preffered way is.
Can the Objective-C gurus shed some light on this?
IMHO, which way is 'right' is a matter of preference. I don't disagree with the responders who advocate not using autorelease, but my preference is to use autorelease unless there is an overwhelmingly compelling reason not to. I'll list my reasons and you can decide whether or not their appropriate to your style of programming.
As Chuck pointed out, there is a semi-urban legend that there's some kind of overhead to using autorelease pools. This could not be further from the truth, and this comes from countless hours spent using Shark.app to squeeze the last bit of performance out of code. Trying to optimize for this is deep in to "premature optimization" territory. If, and only if, Shark.app gives you hard data that this might be a problem should you even consider looking in to it.
As others pointed out, an autoreleased object is "released at some later point". This means they linger around, taking up memory, until that "later point" rolls around. For "most" cases, this is at the bottom of an event processing pass before the run loop sleeps until the next event (timer, user clicking something, etc).
Occasionally, though, you will need to get rid of those temporary objects sooner, rather than later. For example, you need to process a huge, multi-megabyte file, or tens of thousands of rows from a database. When this happens, you'll need to place a NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; at a well chosen point, followed by a [pool release]; at the bottom. This almost always happens in some kind of "loop batch processing", so it's usually at the start and bottom of some critical loop. Again, this should be evidence based, not hunch based. Instrument.app's ObjectAlloc is what you use to find these trouble spots.
The main reason why I prefer autorelease to release, though, is that it is much easier to write leak-free programs. In short, if you choose to go the release route, you need to guarantee that release is eventually sent to obj, under all circumstances. While this seems like it might be simple, it is actually surprisingly hard to do in practice. Take your example, for instance:
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
// Assume a few more lines of work....
[obj release];
Now imagine that for some reason, something, somewhere, subtly violates your assumption that array is mutable, maybe as the result of using some method to process the results, and the returned array containing the processed results was created as a NSArray. When you send addObject: to that immutable NSArray, an exception will be thrown, and you will never send obj its release message. Or maybe something goes wrong somewhere between when obj was allocd and the required call to release, like you check some condition and return() immediately by mistake because it slipped your mind that that call to release later on must take place.
You have just leaked an object. And probably signed yourself up to several days of trying to find out where and why it is your leaking it. From experience, you will spend many hours looking at that code above, convinced that it could not possibly be the source of the leak because you very clearly send obj a release. Then, after several days, you will experience what can only be described as a religious epiphany as you are enlightened to the cause of the problem.
Consider the autorelease case:
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
// Assume a few more lines of work....
Now, it no longer matters what happens because it's virtually impossible to leak obj accidentally, even under extremely unusual or exceptional corner cases.
Both are correct and will work as you're expecting them to.
I personally prefer to use the latter method, but only because I like to be explicit about when objects get released. By autoreleasing the object, all we're doing is saying "this object will get released at some arbitrary point in the future." That means you can put the autoreleased object into the array, destroy the array, and the object might (probably) still exist.
With the latter method, the object would get destroyed immediately with the array (providing that nothing else has come along and retained it in the meantime). If I'm in a memory-constrained environment (say, the iPhone) where I need to be careful about how much memory I'm using, I'll use the latter method just so I don't have so many objects lingering in an NSAutoreleasePool somewhere. If memory usage isn't a big concern for you (and it usually isn't for me, either), then either method is totally acceptable.
They are both correct but B may be preferred because it has no overhead at all. Autorelease causes the autorelease pool to take charge of the object. This has a very slight overhead which, of course, gets multiplied by the number of objects involved.
So with one object A and B are more or less the same but definitely don't use A in scenarios with lots of objects to add to the array.
In different situations autoreleasing may delay and accumulate the freeing of many objects at the end of the thread. This may be sub-optimal. Take care that anyway autoreleasing happens a lot without explicit intervention. For example many getters are implemented this way:
return [[myObject retain] autorelease];
so whenever you call the getter you add an object to the autorelease pool.
You can send the autorelease message at any point, because it isn't acted on until the application's message loop repeats (i.e. until all your methods have finished executing in response to user input).
http://macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=last&x-showcontent=text
You have alloc'ed the object, then it's your job to release it at some point. Both code snippets work merely the same, correct way, with the autorelease way being the potentionally slower counterpart.
Personally speaking, I prefer the autorelease way, since it's just easier to type and almost never is a bottleneck.
They're both OK. Some people will tell you to avoid autorelease because of "overhead" or some such thing, but the truth is, there is practically no overhead. Go ahead and benchmark it and try to find the "overhead." The only reason you'd avoid it is in a memory-starved situation like on the iPhone. On OS X, you have practically unlimited memory, so it isn't going to make much of a difference. Just use whichever is most convenient for you.
I prefer A (autoreleasing) for brevity and "safety", as johne calls it. It simplifies my code, and I've never run into problems with it.
That is, until today: I had a problem with autoreleasing a block before adding it to an array. See my stackoverflow question:
[myArray addObject:[[objcBlock copy] autorelease]] crashes on dealloc'ing the array (Update: Turns out the problem was elsewhere in my code, but still, there was a subtle difference in behavior with autorelease…)

Caption update on button causing IPhone app to crash

I'm currently teaching myself Objective-C and Iphone Development using the very good 'Begining IPhone Development'. I have been playing around with one of the sample applications and I am trying to update one button with text from a text field when another button is pressed. I have set up my Actions and links and all that jazz. The code of the single method/function/call is below
-(IBAction)updateButtonPressed
{
NSString *newCaption = [[NSString alloc] initWithString:#"."];
newCaption = tfUpdateText.text;
[btnPressMe setTitle:newCaption forState:UIControlStateNormal];
[newCaption release];
}
It works perfectly the first time I press the button and maybe for two or three times after then crashes. I'm obviously doing something really stupid but I cant see it. This is all I added (as well as declarations, property - synthesize etc). Can someone point out my obvious memory leak.
Update:
If I change to this
-(IBAction)updateButtonPressed
{
[btnPressMe setTitle:tfUpdateText.text forState:UIControlStateNormal];
}
It works fine but could someone explain to me what mistake I was making?
You are incorrectly managing memory. What is the -initWithString:#"." for? You're generating a constant string #".", then leaking it, then pointing to a different string (tfUpdateText.text), then assigning that pointer to the title, then releasing the -text object.
This is both a leak and an over-release. It's the over-release that's crashing.
Perhaps you meant this:
-(IBAction)updateButtonPressed
{
[btnPressMe setTitle:tfUpdateText.text forState:UIControlStateNormal];
}
You have a memory management bug. The newCaption reference object you are releasing is different from the one you initialized. You are accidentally leaking the NSString you allocated, and releasing tfUpdateText.text instead.
You can remove the temperory variable like:
-(IBAction)updateButtonPressed
{
[btnPressMe setTitle:tfUpdateText.text forState:UIControlStateNormal];
}
You're not using NSString properly here (and are really doing a lot more work than required). NSStrings are just pointers, so your second assignment to newCaption is just orphaning the first. When you then send [newCaption release] later on, you're not sending it to your alloc'd object, but rather to tfUpdateText.text, which you didn't retain. Get rid of the alloc and the release, and you should be all set.