Search code examples
objective-ccocoaclangclang-static-analyzer

Clang: what is "Method returns an Objective-C object with a +0 retain count" trying to tell me?


Running a static analysis with clang in both XCode 3.2 and Nikita Zhuk's Analysis Tool I've often come across this pair of warnings:

Method returns an Objective-C object with a +0 retain count (non-owning reference)

Incorrect decrement of the reference count of an object is not owned at this point by the caller

An example of code that may provoke this warning:

UIButton* button = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame: CGRectMake(x, y, width, height)];
return button;

I assumed that buttons created this way are autoreleased, just like any other NSObject created with a convenience factory method. So I return it, and the caller can decide whether to retain it or not. What's the problem with that?

Am I obliged to retain and autorelease the object before returning it? And most importantly, could whatever this warning is warning against ever be the cause of scary release-related crashes?

I realize now that this seems to only occur with UIButtons. Is it due to it being a class cluster?

EDIT: The snipped below shows a minimal case where clang issues these warnings (with the warnings in bold). Both warnings are flagged on the statement creating the object (the buttonWithType: message).

-(UIButton*) ztupidTezt:(UIImage*) img
{
  UIButton* bt = [[UIButton buttonWithType:UIButtonTypeCustom]initWithFrame:

1 Method returns an Objective-C object with a +0 retain count (non-owning reference)

2 Incorrect decrement of the reference count of an object is not owned at this point by the caller

    CGRectMake(0.0f, 0.0f, img.size.width, img.size.height)];
    bt setImage:img forState:UIControlStateNormal];
    return bt;
}

Solution

  • The cause is most likely the use of sending both a buttonWithType: and initWithFrame: message. init* methods perform tasks that should only be done once for a given object. Class methods that create objects also initialize them. The result of your code is repeated initialization. Instead, send the buttonWithType message, then assign to the frame property.