retainCount in blocks show extrange behavior - objective-c

I got the this code in a class:
- (void)cancel {
if (_cancelBlock)
_cancelBlock();
}
- (void)overrideCancelWithBlock:(void(^)(void))cancelBlock {
[_cancelBlock release];
NSLog(#"AsyncOperation-overrideCancelWithBlock-[cancelBlock retainCount]=%lu (before)", [cancelBlock retainCount]);
_cancelBlock = [[cancelBlock copy] retain];
NSLog(#"AsyncOperation-overrideCancelWithBlock-[_cancelBlock retainCount]=%lu (after)", [_cancelBlock retainCount]);
}
- (void)dealloc
{
NSLog(#"AsyncOperation-dealloc-[_cancelBlock retainCount]=%lu (before)", [_cancelBlock retainCount]);
[_cancelBlock release];
NSLog(#"AsyncOperation-dealloc-[_cancelBlock retainCount]=%lu (after)", [_cancelBlock retainCount]);
[super dealloc];
}
The output for this NSLog()'s are:
AsyncOperation-overrideCancelWithBlock-[cancelBlock retainCount]=1 (before)
AsyncOperation-overrideCancelWithBlock-[_cancelBlock retainCount]=1 (after)
AsyncOperation-dealloc-[_cancelBlock retainCount]=1 (before)
AsyncOperation-dealloc-[_cancelBlock retainCount]=1 (after)
The documentation for the copy method says this:
Special Considerations
If you are using managed memory (not
garbage collection), this method
retains the new object before
returning it. The invoker of the
method, however, is responsible for
releasing the returned object.
So. Way the output of the NSLog() always show the same value for retainCount?

and the documentation for retainCount says this:
Important: This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
To understand the fundamental rules of memory management that you must abide by, read “Memory Management Rules”. To diagnose memory management problems, use a suitable tool:
The LLVM/Clang Static analyzer can typically find memory management problems even before you run your program.
The Object Alloc instrument in the Instruments application (see Instruments User Guide) can track object allocation and destruction.
Shark (see Shark User Guide) also profiles memory allocations (amongst numerous other aspects of your program).
To answer your question: Only apple might know why the retainCount at this point is like it is.

_cancelBlock = [[cancelBlock copy] retain];
That over-retains the block; just -copy it.
Since Blocks can change form at runtime based upon actions taken and change type at compile time based on implementation details, the various Block classes generally treat retainCount as the nonsense generator that it is. In some cases, this will mean returning 1 always.
Note that a retainCount of zero is a logical impossibility in all cases.

Related

How to find where an Objective-C object is referenced from?

I'm using the Allocations instrument in Xcode to track an object that is being created but not released. I can see the object count increase as the code executes, and I can see where the objects are being created using the call stack, but I can't tell where the object references are being held. I think they're being held in a 3rd-party library, but the developer says "no, it must be your code". I'm setting the references in my code to nil, but the objects remain.
I don't think there exists a tool that will tell you where each reference is at any point in time. As you're using ARC, in my experience, there are two fairly common ways to get yourself caught in a reference cycle and leak memory:
Class A has a strong reference to an instance of class B, which has a strongly reference to the same instance of class A.
Blocks implicitly retain references to objects it captures. So one obvious gotcha is when your object retains a block which retains a reference to self.
Example:
self.retainedBlock = ^{
[self doSomething];
};
Fix:
__weak id weakSelf = self;
self.retainedBlock = ^{
id strongSelf = weakSelf;
[strongSelf doSomething];
};
It's a desperation ploy but what you could do is:
disable ARC for the affected object (or work around it; see below);
add a logging retain, autorelease and release;
trace a known over-retained object through your logs.
The simplest example:
- (void)release
{
NSLog(#"%# : %#", self, [NSThread callStackSymbols]);
[super release];
}
(though, in practice, it's probably a lot smarter to keep an array of [NSThread callStackSymbols] for the memory management calls in a dictionary indexed by e.g. [NSValue valueWithPointer:self], then to access that either from lldb or by writing it to disk; why bother effectively indexing the data by hand?)
Probably the easiest way to work around ARC is to write a single class with ARC disabled that can method swizzle your logging memory management methods onto the objects you want to track.

Why does this GCD example code seem to improperly release an object?

In wikipedia example author has released the object stats, when it has not been allocated, copied, or retained. Is this an error or something I don't understood?
- (IBAction)analyzeDocument:(NSButton *)sender
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSDictionary *stats = [myDoc analyze];
dispatch_async(dispatch_get_main_queue(), ^{
[myModel setDict:stats];
[myStatsView setNeedsDisplay:YES];
[stats release];
});
});
}
It is either an error or it is properly documented that analyze returns ownership of the object to the caller. If it is not an error that stats is released then that codes example is using a convention that goes against Apple's memory management rules for ownership.
Memory-management rules, sometimes referred to as the ownership
policy, help you to explicitly manage memory in Objective-C code.
You own any object you create by allocating memory for it or copying
it.
Related methods: alloc, allocWithZone:, copy, copyWithZone:,
mutableCopy, mutableCopyWithZone:
Another prefix that should return ownership is the class method +new. E.g. [MyDocClass newAnalysis];
This is just an example cooked up by John Siracusa to demonstrate how GCD can easily put a long-running task into the background, but, yes, it has one of two problems, one an ingored convention, the other an actual error.
It's possible that the fictional analyze method returns an owning reference. This is a violation of Cocoa convention that methods not named new, alloc, release, or copy... generally don't return such references, but if the documentation made clear that it did, and there was really no way around it, it could be all right. In this case, sending release to stats would be necessary to avoid a memory leak. (If this were real code, renaming the method would be a good idea, perhaps using create which is used in CoreFoundation to signify return of an owning reference.)
If, however, analyze follows convention and returns a non-owned reference, then you're right, sending release to stats is incorrect and will eventually cause a crash.
Most likely analyze is returning a dictionary with a retain count of 1 which is why the release is needed.

release , in Objective C

What I am doing is to check the retainCount after allocating the obj and after releasing this obj. Like below
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
TestClass *ptr = [[TestClass alloc] init];
NSLog(#"retain count of ptr is %d",[ptr retainCount]);
[ptr release];
NSLog(#"Right after release:::::retain count of ptr is %d",[ptr retainCount]);
}
What is getting after display on the console is
2012-05-11 13:51:09.515 memoryManagement[1807:f803] retain count of ptr is 1
2012-05-11 13:51:09.516 memoryManagement[1807:f803] Right after release:::::retain count of ptr is 1
I don't why the retainCount after releasing is still 1. Should it be 0.
Please advice me on this issue and point out if I have just made a mistake in my code.
The first rule of Cocoa Club is: don't use -retainCount. The second rule of Cocoa Club is don't use -retainCount.
First off, if you think you need it, you almost certainly don't. If you are using it to debug, you are using the wrong tool. If you are using it for application logic, you have a broken design.
Second, if you have to ask a StackOverflow question about it, you definitely don't need it.
Third, it's subtle, unreliable, can do wacky things behind your back, and generally will cause more headaches than you can possibly imagine. I recommend Bill Bumgarner's blog post.
The actual retain count of an object can never be zero, because when it's zero, nothing has a reference to it, and it is deallocated. The memory doesn't actually get cleared, though, and it looks like the internal release code doesn't bother actually decrementing the count.
Further, you're violating memory management rules; you've got an object that you own, which you then release. You're not allowed to interact with that object through that pointer anymore.
Nothing to see here, and don't bother looking at an object's retain count.
You have an even worse problem than using retainCount.
Never send messages to objects you release -- especially if you have some reason to think their retainCount is really 1. Maybe release is written something like this:
-(void) release {
if ([self retainCount] == 1) {
[self dealloc];
}
else {
// reduce the retain count
}
}
In that case, the object is gone. You send the message, and if the object is somehow still living in deallocated memory, it would report a retainCount of 1 -- no one says release needs to decrement it if it's being deallocated (who would know?).
Once you call release -- you promised never to send messages to the object -- if you break your promise, anything can happen.
The Apple docs explain why retainCount is not what you think it might be
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html
Important This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
The docs also explain whey you sometimes see a giant number instead of what you think the retainCount should be:
For objects that never get released (that is, their release method does nothing), this method should return UINT_MAX.
This has nothing to do with your case though. If you call retain on ptr right after you init, you will likely see the retainCount as 2 and 1 (or N and N-1), but are not guaranteed that this is true. retainCount is more logical than a lot of these answers would have you believe, but it can't be used in the way you want to reliably.
Never use retainCount. It is confusing and never gives you a clear answer. Also, If you are correctly following memory management guidelines, you would never need to use retaincount.
On most occasions, it gives you ambiguous output.
Eg. [NSString stringwithstring:#"apple"] has a garbage value as retaincount like 1124523415 etc.
So, never trust retainCount.

Differences in return object pointer?

Can someone explain the difference between these two, the first one is taken from allowing xcode to automatically generate the declaration, the last one is taken from an example in "Cocoa Programming" by Aaron Hillegass.
- (NSString*)planetName {
return [[planetName retain] autorelease];
}
.
- (NSString*)planetName {
return planetName;
}
I am just curious whats going on, my understanding was that the method is returning a pointer to either nil or an existing string object. I don't understand the reason for retaining and then adding to the autorelease pool?
Consider:
NSString *planetName = [myPlanet planetName];
[myPlanet setPlanetName: #"Bob"];
[planetName length];
Without [[planetName retain] autorelease], the above will very likely crash.
retain/autorelease puts the object into the current thread's autorelease pool. That effectively guarantees that the object will remain valid until the pool is drained, which is typically after the current event -- user event, timer firing, etc... -- is done processing.
(1) Use #property and #synthesize. It generates correct getter/setters for you.
(2) Read the Cocoa Memory Management guide. It answers all of these questions quite well.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
In both cases, yes, they are both returning a pointer to either nil or the string object.
The difference is that the first code block handles memory management, the second does not. The second code block is assuming you are managing planetName somewhere else in your class instance, whereas in the first code block Apple is being as conservative as possible in keeping that memory from leaking. By putting the memory in the current autorelease pool it will be destroyed with the pool.
My recommendation would be to stick with the latter case and to be a little wiser about managing your own object instances than what XCode is auto-generating for you.

What does the retain message mean?

In Objective-C I see
[object retain];
What does sending a retain message to an object mean and why would I use it?
Basically it is used to take 'ownership' on an object, i.e. by calling retain, the caller takes the responsibility of handling memory management of that object.
Two very common usages of the top of my hat are:
1- you initiate an object with auto memory managed methods, but want it to hang around some time : someObject = [[someArray objectAtIndex:someIndex] retain], without retain the object will be autoreleased at some time you don't control.
2- you initiate an object by passing somePointer to it, you do your memory management and call release on somePointer, and now somePointer will hang around until the newly initiated object releases it, the object calls retain on somePointer and now owns it.
-(id) initWithSomePointer:(NSObject *)somePointer_{
if(self = [super init])
somePointer = [somePointer_ retain];
return self;
}
..
..
[somePointer release];
It ups the reference count on the object in question.
See this post for more details about reference counting in Objective C.
Read Apple's memory management guide for a complete and pretty simple explanation of everything to do with Cocoa memory management. I strongly recommend reading that rather than depending on a post on Stack Overflow.