views:

129

answers:

3

Hello,

I did the "Build and analyze" in xCode and get "Dereference of null pointer" when setting a normal int to 0 in my init-method. I noted in my code below for which row I get the message. I'm developing for iPhone.

Bric.m

#import "Bric.h"

@implementation Bric

- (id)initWithImage:(UIImage *)img:(NSString*)clr{
    if (self = [super init]) {
        image = [[UIImageView alloc] initWithImage:img];
    }   

    stepX = 0; //It's for this line I get the message
    stepY = 0;
    oldX = 0;
    color = [[NSString alloc]initWithString:clr];
    visible = YES;
    copied = NO;
    return self;
}   
@end

Bric.h

#import <Foundation/Foundation.h>

@interface Bric : NSObject {

    int stepX;
    int stepY;

}  

-(id)initWithImage:(UIImage *)img:(NSString *)clr;

@end

It's not the complete code, pasted what I think is useful.

Since I am not using a pointer I find this quite strange. How come I get this message?

Thanks and Regards, Niklas

A: 

Hi. Have you declared it as a property? I'm not sure if it's necessary in this case but you haven't made accessor methods (although I think you are still setting the instance variable directly...)

i.e., in your header file,

@property int stepX;

and in your .m file,

@synthesize stepX;

This will allow you to access the variable as self.stepX and self.stepY. Sometimes the analyzer makes mistakes though... I noticed that it doesn't deal with while loops very effectively. Anyway, see what happens if you add those lines of code and get back to me.

Helen
Thank you for your answer. But this didn't help, and since it is a primitive it shouldn't be necessary if I'm not mistaken (never done it before at least and never had a problem with that).
Nicsoft
Actually, in my experience, the analyser copes with while loops pretty well. Are you completely sure the issues it flagged weren't real?
JeremyP
Pretty sure. It was a "while not done" loop and it said that the "not done" variable (which was set to false during the loop) was "set but never read".Sorry about the unhelpful post.
Helen
+6  A: 

The first if statement in your init method is checking whether or not [super init] returns nil. (Technically it should be written if ((self = [super init])), which the new LLVM compiler will warn you about).

The static analyser is checking ALL possible code paths, even the case where [super init] returns nil. In this case, your if statement fails and self is nil. If self is nil then its instance variables aren't accessible.

To fix this, you need to place your initialisations inside the if statement with the image initialisation and then return self outside the if statement.

Jasarien
Thanks, I understand now. This fixed the problem. I guess I shouldn't need to write "if ((self = [super init]))", you just wrote that for pedagogic reaons, rigth? Never seen double parantheses before at that place.
Nicsoft
The double parentheses tell the compiler to evaluate the `self = [super init]` first and then evaluate the result as a boolean after.With the new LLVM compiler, not having double parentheses around an assignment in an `if` statement will generate a warning, because the compiler is "intelligently" asking if you meant to use `==` instead of `=` (which is a common mistaken when doing something like `if (x == 5)`.
Jasarien
A: 

Your init method is wrong.

It should look like this:

- (id)initWithImage:(UIImage *)img:(NSString*)clr
{
    if (self = [super init])  // NB, this line should give you a waring
    {  
        image = [[UIImageView alloc] initWithImage:img];
        stepX = 0; //It's for this line I get the message
        stepY = 0;
        oldX = 0;
        color = [[NSString alloc]initWithString:clr];
        visible = YES;
        copied = NO;
    }   
    return self;
}

I assume the message you are getting is from the static analyser. As stepX is an instance variable, the line

stepX = 0;

is really shorthand for

self->stepX = 0;

where -> has its normal C meaning. As that line is outside the test that self is non nil in your code, the static analyser is flagging an issue.

JeremyP
Thanks for your answer. Why should I get a warning at "if (self = [super init])"? I didn't get it with my old code and neither when using the changes you provided... The warning was at the first row after the if-clause, that's at row "stepX = 0;" in my code posted above. I guess it's the way for the analyzer to tell me that the stepX-row shouldn't be there (and me together with stackoverflow has to figure out that it should be inside the if-clause...).
Nicsoft
It's a safety feature to guard against accidentally writing = when you mean ==. You might have that warning turned off.
JeremyP