Should this value be released? - ios

I was getting a segfault 11 memory access error in the IOS Simulator, but it disappears when I comment out the release in the code below.
// get get the question number
NSString *text = [attributeDict valueForKey:XML_TAG_QUESTION_ATTRIBUTE_NUMBER];
question.number = [text intValue];
//[text release]; <==== no more segfault 11 when this is commented out.
My question is, since I am receiving an instance of NS String returned by the NSXMLParser implementation, isn't the reference count increased and should I not be releasing it?

Here's the rule: Always NARC on your memory management.
If you call:
(N)ew
(A)lloc
(R)etain or
(C)opy...
You need to release. If not, you got it through a convenience method and it's autoreleased.
In the case of containers of other objects, the container has the objects retained, and you don't need to worry about it until you release the container.

No it should not.
Read the memory management programming guide : http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/MemoryMgmt.html

Related

Is there any leak in NSAutoreleasepool?

What will be result ? is there any leak or crash??
-(NSString)returnPersonName {
NSAutorelease *pool = [[NSAutorelease alloc]init];
NSString *name = [[[NSString alloc]initWithString:#"Name"]autorelease];
[pool drain];
return name
}
bit confusing to me.
This code violates memory management rules. You do alloc, so you get ownership of a +1 reference count, and then you do autorelease on it, by which you give up your ownership of the reference count. Therefore, you should not use name anymore, and it is not guaranteed to point to a valid object. You return it, a pointer to a potentially invalid object.
In this particular case, because of the implementation details of Cocoa, nothing "bad" will happen. The body of that function is equivalent to just return #"Name";. #"Name" is a string literal, and string literals are stored in static storage that exists for the entire lifetime of the program. That means those string objects are not subject to memory management -- retain, release on them have no effect. You do [[NSString alloc] init...] on it, but NSString's initializers are optimized to simply retain and return its argument if the argument is already an immutable string. So you are not returning a new NSString object; you are just returning the same string literal which is statically allocated and not subject to memory management. Again, all this is implementation details of Cocoa that you cannot rely on.
I'm tipping the above could potentially crash because [pool drain] will cause name to be deallocated before it can be returned.
In a reference-counted environment, the drain method behaves the same as release. Since an autorelease pool cannot be retained, this therefore causes the receiver to be deallocated. When an autorelease pool is deallocated, it sends a release message to all its autoreleased objects. If an object is added several times to the same pool, when the pool is deallocated it receives a release message for each time it was added.
The pool is not required, for something like this try -
-(NSString*)returnPersonName {
NSString *name = [[[NSString alloc]initWithString:#"Name"]autorelease];
return name;
}
More info can be found in the Advanced Memory Management Programming Guide
On a side note - an #autorelease { } pool block is better to use than NSAutoreleasePool and even better is switch to ARC!

Why this doesn't crash? [duplicate]

This question already has answers here:
Objective-C autorelease pool not releasing object
(2 answers)
Why can I send messages to a deallocated instance of NSArray?
(2 answers)
Closed 9 years ago.
Why the second line in the loop (the a.retainCount one) won't crash (due to bad access) ?
NSArray* a0 = #[[NSMutableString stringWithString:#"a"]];
NSArray * arr = [NSArray arrayWithObject:a0];
[a0 release];[a0 release];
for (NSArray* a in arr)
{
//NSLog(#"%d", (a == a0) );
NSLog(#"RC: %d", a.retainCount);
}
but it would crash if the first line in loop (a == a0 one) is un-commented.
This would definitely crash when the autorelease pool is drained, but I am specifically asking about the second line in loop, not afterwards.
Can anyone please explain?
Please review http://www.whentouseretaincount.com/
Sending a message to a deallocated object is undefined behavior. It may crash, it may not.
In this case, it isn't crashing because the memory that contained the object hasn't been overwritten by something else. If you were to turn on Malloc Scribble, it'd crash. That call to NSLog() coincidentally causes the memory to be scribbled upon, causing the crash.
retainCount can never return 0 exactly because messaging a deallocated object is undefined behavior. The system doesn't bother decrementing the RC to 0 because the object is no longer viable anyway.
I'm curious within what context this question came up? Are you using a tutorial or class materials that use retainCount?
It isn't always a segmentation fault for the same reason the runtime doesn't decrement the retain count to 0; efficiency.
To make it a guaranteed segmentation fault would mean wasting a few cycles writing bogus values to the memory (or decrementing the retain count).
As it is, free() just marks the memory as being available for future malloc()s. It doesn't modify the contents of the memory in any way, hence the undefined behavior.
This could crash any time. Likely the first line in the loop triggered the memory at the dangling pointer "a" allocated for other use. So when "a" is referenced on the second line, anything could happen.
If you turn on the XCode options in "Scheme -> Diagnostics -> Memory Management", this may crash immediately.

iOS 5 blocks crash only with Release Build

I have using blocks and ARC, and found in some situation, iOS only crash in Release build. It was wrong way to write code, like this.
-(IBAction)clickedButtonA:(UIBarButtonItem*)sender event:(UIEvent*)event {
NSMutableArray *arrRows = [NSMutableArray arrayWithCapacity:0];
#warning this code only crash on Release Build.... Don't use this
NSMutableDictionary * dicRow = [NSMutableDictionary dictionaryWithCapacity:0];
[arrRows addObject:dicRow];
dispatch_block_t block = ^{
NSString *str = [NSString stringWithFormat:#"%#",[_tweet valueForKey:#"text"]];
[[UIPasteboard generalPasteboard] setString:str];
};
[dicRow setValue:block forKey:kDicKeyLinkPopBlock];
NSMutableArray *sections = [NSMutableArray arrayWithObject:arrRows];
TOVLinkPopoverViewController *controller= [[TOVLinkPopoverViewController alloc] init];
controller.arrayLink = sections;
}
And from other controller, when I access the block, it crashes only I am on release build. I have learn you need to copy the block
[dicRow setValue:[block copy] forKey:kDicKeyLinkPopBlock];
For non-block aware Class like NSMutableDictionary.
The question is "Why it only crashes on Release build?" I know this "should crash", and this was wrong way of using block, but hoping it crashes on Debug build so we can find this kind of bug earlier.
One more question is "Is there any build setting that makes this code crash with debug build?"
You can ran sample code from gitHub,
https://github.com/tomohisa/iOS_PopoverMenu_Notification
See ViewController.m and find commented out code (only crash on release).
You're right that you need to add [block copy]. This is because that block is created in the current stack frame (i.e. within clickedButtonA:event:) but then you add it to a dictionary and presumably pull it out later. When you pull it out later and use it, that original stack frame has gone and you will have a pointer to some random memory that might not (most likely won't) actually be the block any more.
When you copy the block, if it's on the stack currently then it gets copied to the heap and if it's already on the heap then it just retains it. This means that you now have a block which can be passed around between contexts and will be valid.
The reason that you are only seeing it crash in release mode is because release mode will be turning on compiler optimisation that is completely changing how the stack is handled. Probably you were very lucky in debug mode not to see the problem and was simply a quirk of how your app is designed.

Using Zombies in Xcode

I am using Zombies to try and get rid of an EXC_BAD_ACCESS error.
In Zombies, I got this message when the app crashes -
An Objective-C message was sent to a deallocated object (zombie) at
address: 0x8955310.
My question is what do I do next to solve the problem ?
Turn on malloc stack logging and zombies for your scheme in Xcode, and run the app in the simulator. Xcode should enter the debugger when the message is sent to the zombie. Run this command at the debugger prompt:
info malloc 0x8955310
(Substitute the actual address of the zombie!) You'll get stack traces from when that address was allocated and freed.
Most likely you have created an object, released it and later sent it a message.
To make sure this won't happen, a safe practice would be to set your object to nil once you are done using it
Consider:
NSMutableArray *a = [NSmutableArray array];
[a dealloc];
[a do_something_weird];
Your app is likely crash (won't always crash) in response to this message, as after release, you don't own this memory, and it may be used by some other object.
If you change this sequence to
NSMutableArray *a = [NSmutableArray array];
[a dealloc];
a=nil;
[a do_something_weird];
Exactly nothing will happen. This is a safe practice to follow when you are sure you're done using the object.
You also may want to consider using the Automatic Reference Counting feature, which helps a lot with memory management.

Can't figure out memory leak testing with simulator and in general

EDIT: guys, my question was about using the Instruments to see leaks, and the code as an example and side question, but you answered the side question and not the main problem.... Thank you for the answers, but I really need to find out how to work the Instruments with the simulator....
I am learning IOS development, In one of the codes I'm studying i think there is huge memory leak so I've tried learning how to use instruments. As i am learning right now, I am trying to use instruments with the simulator, but all the manuals i found are for connecting to a device and then using instruments and not with the simulator. every thing I've tried doesn't show any leaks in Instruments.
The app doesn't crash because i am guessing the memory leak is not that big, but when i am adding the following code it does crash, why is that, Even when i added the release every time, still crashes....what is wrong with the simulator? or with the code? working with xcode3, not 4.
for (int i = 0; i < 1000000; i++) {
NSString *testLeak = [[NSString alloc] initWithString:#"test1223"];
NSLog(#"%#",testLeak);
[testLeak release];
}
And again, the app crashes and the simulator doesn't show any leaks, even when i put the "attach process" on "iPhone simulator".
NSString *testLeak = [[NSString alloc] initWithString:#"test1223"];
The problem is that you are not actually allocating anything. NSString is internally smart enough to recognize that the above expression does not need to allocate anything because the constant string #"test1223" can neither mutate nor ever be deallocated. Thus, it just returns that string.
If you were to NSLog(#"%p", testLeak); you'd see the same address over and over.
Change the NSString to NSMutableString and you'll likely see the thousands of copies. Maybe; NSMutableString could be optimized to just point to the immutable copy until a mutation operation is performed (implementation detail). Or you could allocate an instance of some class of your own creation.
Keep in mind that Leaks doesn't necessarily show you all leaks; it can't because of the way it works.
For this kind of analysis, Heapshot analysis is very effective.
If it is crashing as described, please (a) post the crash log and (b) file a bug with your app (built for the simulator) attached to http://bugreport.apple.com/.
In general Instruments + Simulator will not be terribly useful; the simulator is only an approximation of what is running on the device.
[something release] doesn't actually free the memory the instant it is called - it just decreases the reference count of an object. If the count is 0, a [something dealloc] is called, and that frees the memory. I guess you are allocating memory faster than the system can free it... besides, doing 1.000.000 allocs in rapid succession instead of single huge one is probably as bad a coding practice as they come...
It may be that some stuff is getting autorelease'd, and that is using a ton of the heap. Try changing your code to this:
for (int i = 0; i < 1000000; i++) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testLeak = [[NSString alloc] initWithString:#"test1223"];
NSLog(#"%#",testLeak);
[testLeak release];
[pool drain];
}
Thank you all, I actualy Found the answer around 4 am yestorday...
when you want to test leaks on the emulator:
rum -> run with Performance Tool ->Leaks
If you select the simulator on the top right as the device to run the app on, It will lounch the simulator and the instruments and start the leak recorder, all in one click....
Have fun :-)
Erez

Resources