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

I have a very simple Person class that has a ivar called name ( an NSString). When I try to release this ivar in dealloc the static analyzer gives me a weird error:
Incorrect decrement of the reference
count of an object that is not owned
at this point by the caller
What am I doing wrong?
BTW, here's my code:
#interface Person : NSObject {
}
#property (copy) NSString *name;
#property float expectedRaise;
#end
#implementation Person
#synthesize name, expectedRaise;
-(id) init {
if ([super init]) {
[self setName:#"Joe Doe"];
[self setExpectedRaise:5.0];
return self;
}else {
return nil;
}
}
-(void) dealloc{
[[self name] release]; // here is where I get the error
[super dealloc];
}
#end

You're releasing an object returned from a property getter method, which in many cases would be the indication of a possible bug. That's why the static analysis is picking it up.
Instead, use:
self.name = nil;
or:
[name release];
name = nil;

Related

NSMutableArray empty after created in init (with code)

#property (nonatomic, strong) NSMutableArray *authorMutableArray;
- (id)init {
self = [super init];
if (self) {
self.authorMutableArray = [[NSMutableArray alloc] initWithObjects:#"First Row", #"Second Row", nil];
for (NSString *string in authorMutableArray) {
NSLog(#"String: %#", string);
}
NSLog(#"Init in Add Model with Author count:%i", [authorMutableArray count]);
}
}
An example of accessing the property. The NSLog always shows the count as 0.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
if (indexPath.row == [self.addModel.authorMutableArray count] - 1 ) {
NSLog(#"count of %i", [self.addModel.authorMutableArray count]);
return UITableViewCellEditingStyleInsert;
}
else {
return UITableViewCellEditingStyleDelete;
}
}
else {
return UITableViewCellEditingStyleNone;
}
}
The array I'm creating in init is not keeping its values past this method. Any reason why? The for loop will show both objects in the array. If I try to ask this after the init method is called, the array is empty.
Updated: Thank you everyone for your time and eyes. I had forgotten to return self in the init method.
Shouldn't the init method return self ?
In your class' interface file(.h file) declare like this:
#interface Your_Class_Name : UIViewController {
NSMutableArray *authorMutableArray;
}
#property (nonatomic, strong) NSMutableArray *authorMutableArray;
//i dont know why you prefered strong, chose retain and try again please
We aren't dealing with C++ or Java here, the -init method of an object MUST return a value.
This quirk actually allows for some pretty interesting stuff, e.x. the following:
-(id) init {
NSLog(#"Creating new instance of singleton object...");
#if __has_feature(objc-arc)
self = singleton_instance;
#else
[self release];
self = [singleton_instance retain];
#endif
return self;
}
It also allows for class 'posing' of a sort, allowing you to track exactly when an object of a particular class is initialized (that is too deep of a topic for this answer).

How to release property of static class

i have a static class witch has two property,like below ...
#interface Global : NSObject
{
BarcodeScanner* scanner;
NSInteger warehouseID;
}
#property(assign) BarcodeScanner* scanner;
#property(assign) NSInteger warehouseID;
+(Global *)sharedInstance;
#end
#import "Global.h"
#implementation Global
#synthesize scanner,warehouseID;
+ (Global *)sharedInstance
{
static Global *globalInstance = nil;
if (nil == globalInstance) {
globalInstance = [[Global alloc] init];
globalInstance.scanner = [[BarcodeScanner alloc] init];
globalInstance.warehouseID = 1;
}
return globalInstance;
}
-(void) dealloc
{
[super dealloc];
}
#end
now when i analyze project in Xcode i got warning for memory leak for scanner and warehouseID properties , and when i try to release them in dealloc method like ...
[[[Global sharedInstance] scanner]release];
i got warning "incorrect decrement of the reference count of an object..."
how should i resolve this problem.
so thanks for any help.
The warning is because your code does not match the rules Analyzer uses. To avoid the warning
make the scanner property retain
change the the instantiation or BarcodeScanner to be autorelease
add a release for scanner in dealloc
Example (reformatted just to save space):
#class BarcodeScanner;
#interface Global : NSObject {
BarcodeScanner* scanner;
NSInteger warehouseID;
}
#property(retain) BarcodeScanner* scanner;
#property(assign) NSInteger warehouseID;
+(Global *)sharedInstance;
#end
#implementation Global
#synthesize scanner,warehouseID;
+ (Global *)sharedInstance {
static Global *globalInstance = nil;
if (nil == globalInstance) {
globalInstance = [[Global alloc] init];
globalInstance.scanner = [[[BarcodeScanner alloc] init] autorelease];
globalInstance.warehouseID = 1;
}
return globalInstance;
}
-(void) dealloc {
[scanner release];
[super dealloc];
}
#end
just leave it to autorelease pool
globalInstance.scanner = [[[BarcodeScanner alloc] init] autorelease];

Mutable array contents are lost between methods

I have this code in my .m file, which is a Cocos 2D CCLayer class. I initialize an array in the init method and then I try to use contents of this array in the nextFrame method. But when the nextFrame method gets called, the contents of the array seem empty. When I try to get the first item, I receive an error message saying:
Program received signal "EXC_BAD_ACCESS"
How can I successfully access the contents of this array in my nextFrame method?
NSMutableArray *cars;
-(id) init {
cars = [NSMutableArray array];
Car *car;
car = [[Car alloc] init];
[cars addObject:car];
self.isTouchEnabled = YES;
}
- (void) nextFrame:(ccTime)dt {
Car *car = [cars objectAtIndex:i]; // Program received signal "EXC_BAD_ACCESS"
}
Car.h
#import <Foundation/Foundation.h>
#import "cocos2d.h";
#interface Car : NSObject {
NSInteger type;
CCSprite *sprite;
}
#property (readwrite, assign) NSInteger type;
#property (retain) CCSprite *sprite;
#end
Car.m
#import "Car.h"
#implementation Car
#synthesize type;
#synthesize sprite;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void) dealloc {
[sprite release];
[super dealloc];
}
#end
You're assigning the result of [NSMutableArray array] to an instance variable. That is an autoreleased object, which essentially means it doesn't have any owners and thus will feel free to go away after the current runloop iteration*. You need to retain it if you want it to stick around (or just use [[NSMutableArray alloc] init], which returns an object you own).
* Basically. You should see the Cocoa memory mangement guide for more details. It's pretty short but full of essential information.

Memory leak with objective-c on alloc

When I use Instruments to find memory leaks, a leak is detected on
Horaires *jour;
jour= [[Horaires alloc] init]; // memory leak reported here by Instruments
self.lundi = jour;
[jour release];
and I don't know why there is a leak at this point.
Does anyone can help me? Here's the code.
// HorairesCollection.h
#import <Foundation/Foundation.h>
#import "Horaires.h"
#interface HorairesCollection : NSObject < NSCopying > {
Horaires *lundi;
}
#property (nonatomic, retain) Horaires *lundi;
-init;
-(void)dealloc;
#end
// HorairesCollection.m
#import "HorairesCollection.h"
#implementation HorairesCollection
#synthesize lundi;
-(id)copyWithZone:(NSZone *)zone{
HorairesCollection *another = [[HorairesCollection alloc] init];
another.lundi = [lundi copyWithZone: zone];
[another autorelease];
return another;
}
-init{
self = [super init];
Horaires *jour;
jour= [[Horaires alloc] init]; // memory leak reported here by Instruments
self.lundi = jour;
[jour release];
return self;
}
- (void)dealloc {
[lundi release];
[super dealloc];
}
#end
// Horaires.h
#import <Foundation/Foundation.h>
#interface Horaires : NSObject <NSCopying>{
BOOL ferme;
BOOL h24;
NSString *h1;
}
#property (nonatomic, assign) BOOL ferme;
#property (nonatomic, assign) BOOL h24;
#property (nonatomic, retain) NSString *h1;
-init;
-(id)copyWithZone:(NSZone *)zone;
-(void)dealloc;
#end
// Horaires.m
#import "Horaires.h"
#implementation Horaires
-(BOOL) ferme {
return ferme;
}
-(void)setFerme:(BOOL)bFerme{
ferme = bFerme;
if (ferme) {
self.h1 = #"";
self.h24 = NO;
}
}
-(BOOL) h24 {
return h24;
}
-(void)setH24:(BOOL)bH24{
h24 = bH24;
if (h24) {
self.h1 = #"";
self.ferme = NO;
}
}
-(NSString *) h1 {
return h1;
}
-(void)setH1:(NSString *)horaire{
[horaire retain];
[h1 release];
h1 = horaire;
if (![h1 isEqualToString:#""]) {
self.h24 = NO;
self.ferme = NO;
}
}
-(id)copyWithZone:(NSZone *)zone{
Horaires *another = [[Horaires alloc] init];
another.ferme = self.ferme;
another.h24 = self.h24;
another.h1 = self.h1;
[another autorelease];
return another;
}
-init{
self = [super init];
return self;
}
-(void)dealloc {
[h1 release];
[super dealloc];
}
#end
You've set your property to retain and you alloc and release the variable, so from what I can see the code is okay and Instruments has given you a false warning.
I think your copyWithZone: might have a leak, though. [lundi copyWithZone:] will retain a copy of lundi but you never release it. So you need an extra release, something like this:
-(id)copyWithZone:(NSZone *)zone{
DefibHoraires *another = [[DefibHoraires alloc] init];
Horaires* makeCopy = [lundi copyWithZone: zone];
another.lundi = makeCopy;
[makeCopy release];
return another;
}
This is because copy and alloc both return retained object instances and you need to manually release them when you're finished with them. You did that correctly for your alloc'd objects but not the copy.
That init method looks ok, although it should be implemented (and typed) as
-(id)init
{
if (self = [super init])
{
...
}
return self;
}
or a similar pattern.
Your copyWithZone implementations are wrong, they need to return a retained object, so do not autorelease the returned value. But you need to release your copy of lundi, because you are using the retaining setter.
-(id)copyWithZone:(NSZone *)zone{
DefibHoraires *another = [[DefibHoraires alloc] init];
Horaires *lundiCopy = [lundi copyWithZone:zone];
another.lundi = lundiCopy;
[lundiCopy release];
return another;
}
I don't know why you return an instance of DefibHoraires here, shouldn't it be a HorairesCollection?
Maybe the wrong copyWithZone: method is responsible for the reported leak (it's a leak anyway).
One further note: It's a good defensive rule to use (copy) for NSString properties instead of (retain) to remove side effects when passing NSMutableString instead.
I don't have an answer but I do have some general comments:
In copyWithZone: you should use allocWithZone: (passing the same zone as a parameter) to allocate the object you are going to return.
copyWithZone: should return a retained object. Don't autorelease it.
You are not supposed to use properties in init. Your init should look something like:
-init
{
self = [super init];
if (self != nil)
{
lundi = [[Horaires alloc] init]; // assign the ivar directly
}
return self;
}
In your copyWithZone: for HorairesCollection you have a leak. It should look like:
-(id)copyWithZone:(NSZone *)zone{
DefibHoraires *another = [[DefibHoraires allocWithZone: zone] init];
another.lundi = [[lundi copyWithZone: zone] autorelease];
return another;
}

incompatible Objective-c types warning

I have a user class that I use through the iPhone application, this is the init and initWithUser functions from my user class (A SUBCLASS OF NSobject), when I use the initWithUser function I get the warning described after the code. please advise.
// serialize.h
#import <Foundation/Foundation.h>
#protocol Serialize
// serialize the object to an xml string
-(NSString*)ToXML;
#end
// user.h
#import <Foundation/Foundation.h>
#import "Serialize.h"
#import "Contact.h"
#interface User : NSObject <Serialize> {
NSString *email;
NSString *firstName;
NSString *lastName;
NSString *userId;
NSString *userName;
NSString *password;
NSMutableArray *contactList;
}
#property (nonatomic,copy) NSString *email;
#property (nonatomic,copy) NSString *firstName;
#property (nonatomic,copy) NSString *lastName;
#property (nonatomic,copy) NSString *userId;
#property (nonatomic,copy) NSString *userName;
#property (nonatomic,copy) NSString *password;
#property (nonatomic, retain) NSMutableArray *contactList;
//-(id)init;
-(id)initWithUser:(User *)copyUser;
#end
// user.m
#import "user.h"
#implementation User
#synthesize email;
#synthesize firstName;
#synthesize lastName;
#synthesize userId;
#synthesize userName;
#synthesize password;
#synthesize contactList;
-(id)init
{
// call init in parent and assign to self
if( (self = [super init]) )
{
// do something specific
contactList = [[NSMutableArray alloc] init];
}
return self;
}
-(id)initWithUser:(User *)copyUser
{
if( (self = [self init]) ) {
email = copyUser.email;
firstName = copyUser.firstName;
lastName = copyUser.lastName;
userId = copyUser.userId;
userName = copyUser.userName;
password = copyUser.password;
// release contactList initialized in the init
[contactList release];
contactList = [copyUser.contactList mutableCopy];
}
return self;
}
- (void)dealloc
{
// TODO:
[contactList removeAllObjects];
[contactList release];
[super dealloc];
}
// implementation of serialize protocol
-(NSString*)ToXML
{
return #"";
}
and I use it in the main controller this way
- (void) registerNewUser {
RegistrationViewController *regController = [[RegistrationViewController alloc] init] ;
regController.newUser = [[User alloc] initWithUser:self.user];
[self.navigationController pushViewController:regController animated:YES];
[regController release];
}
the line
regController.newUser = [[User alloc] initWithUser:self.user];
gives me the following error, and its been driving me nuts for a couple of days:
incompatible Objective-c types 'struct User*', expected 'struct NSString *' when passing argument 1 of 'initWithUser:' from distinct Objective-c type
any help and guidance is appreciated
The problem is you have an ambiguous selector. Because alloc returns id, the call to initWithUser: has become ambiguous. NSUserDefaults also has an initWithUser: function which takes a string. The compiler thinks you're trying to use that one. Change the line to
regController.newUser = [(User*)[User alloc] initWithUser:self.user];
and everything should work as expected.
As mentioned in the comments, there are other problems with your implementation. In your initializer, reusing the -init is redundant and the assignments to ivars like email should be taking ownership of the data using -copy or -retain:
-(id)initWithUser:(User *)copyUser {
if((self = [super init])) {
// take ownership of the users data by copying or retaining:
email = [copyUser.email copy];
// ...
contactList = [copyUser.contactList mutableCopy];
}
return self;
}
In -dealloc, -removeAllObjects can be removed and the member data has to be released:
- (void)dealloc {
[email release];
// ...
[contactList release];
[super dealloc];
}
Note that you are also leaking the new User instance if newUser is a copy or retain property as there is a release missing:
User *user = [[User alloc] initWithUser:self.user];
regController.newUser = user;
[user release];