nil argument error

Discussion in 'iOS Programming' started by AlbuquerqueApac, May 8, 2012.

  1. AlbuquerqueApac macrumors member

    Joined:
    Jan 13, 2012
    #1
    Ok, so I will preface this by saying this is NOT my code and I am doing this exercise to help learn. In fact, this came from a book and I have read over it several times and it appears correct.

    ViewController.m
    Code:
     
    
    
    //
    //  ViewController.m
    //  Calculator
    //
    //  Created by on 5/1/12.
    //  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
    //
    
    #import "ViewController.h"
    #import "Calculator.h"
    #import "Fraction.h"
    
    
    @implementation ViewController {
    
    
    
    
    //instance variables (though I think I would of set these up as object properties
    
    char op;
    int currentNumber;
    BOOL firstOperand, isNumerator;
    
    Calculator *myCalculator;   //I'm not sure why this isn't instantiated as an //object?
        
    
    NSMutableString *displayString;
    
    }
    
    @synthesize display;
    
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Release any cached data, images, etc that aren't in use.
    }
    
    #pragma mark - View lifecycle
    
    - (void)viewDidLoad
    {
        //overrided the initiall loading
        
        firstOperand = YES;
        isNumerator = YES;
    
       displayString = [NSMutableString stringWithCapacity:40];
        
       Calculator *myCalculator = [[Calculator alloc]init];
     
       //I'm guessing the above is the reference for the myCalculator object in //"clickEQUALS"
     
    }
    
    -(void)processDigit:(int)digit
    {
        currentNumber = currentNumber * 10 + digit;
        
        [displayString appendString: [NSString stringWithFormat: @"%i", digit]];
        
        display.text = displayString;
        
    }
    
    - (IBAction)clickDigit:(UIButton *)sender
    {
        
        int digit = sender.tag; 
        
        [self processDigit:digit]; 
        
    }
    
    -(void) processOp:(char)theOp
    {
        NSString *opString;
        
        op = theOp;
        
        switch (theOp) { 
            case '+': 
                opString = @"+";
                break;
            case '-':
                opString = @"-";
                break;
            case '*':
                opString = @"x";
                break;
            case '/':
                opString = @"/";
                break;
                
        }
    
        [self storeFracPArt];
        
        firstOperand = NO;
        isNumerator = YES; 
        
        [displayString appendString: opString];
        
        display.text = displayString; 
        
    }
    
    -(void) storeFracPArt
    {
        if (firstOperand) { 
            if (isNumerator) {
                myCalculator.operand1.numerator = currentNumber;
                myCalculator.operand1.denominator = 1;}
            else 
                myCalculator.operand1.denominator = currentNumber; 
            }
        else if (isNumerator) { 
            myCalculator.operand2.numerator = currentNumber;
            myCalculator.operand2.denominator= 1;
            }
        else
        { 
            myCalculator.operand2.denominator = currentNumber;
            firstOperand = YES; 
        }
        currentNumber = 0;
        
    }
     
    -(IBAction)clickOver
    {
        [self storeFracPArt];
        isNumerator = NO;
        [displayString appendString: @"|"];
        display.text = displayString;
    }
    
    //arithmetic operations
    
    -(IBAction) clickPlus
    {
        [self processOp: '+'];
        
    }
    
    -(IBAction)clickMinus
    {
        [self processOp: '-'];
        
    }
    
    -(IBAction)clickMultiply
    {
        [self processOp: '*'];
        
    }
    
    -(IBAction)clickDivide
    {
        [self processOp: '/'];
        
    }
    
    //misc buttons 
    
    -(IBAction)clickEquals
    {
        if ( firstOperand == NO) {
            
            //Calculator *myCalculator = [[Calculator alloc]init];
            
            [self storeFracPArt];
            [myCalculator performOperation: op];
            [displayString appendString: @"="];
            
            [displayString appendString: [myCalculator.accumulator convertToString]];
            
            display.text=displayString;
            
            
            currentNumber=0;
            isNumerator=YES;
            firstOperand=YES;
           [displayString setString:@""];
            
        
            
            
            
            
        }
        
        
    }
    
    -(IBAction)clickClear
    {
        isNumerator= YES;
        firstOperand = YES;
        currentNumber = 0;
        [myCalculator clear];
        [displayString setString:@""];
        display.text=displayString;
        
        
    }
    
    
    
    
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
    }
    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
    	[super viewWillDisappear:animated];
    }
    
    - (void)viewDidDisappear:(BOOL)animated
    {
    	[super viewDidDisappear:animated];
    }
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        // Return YES for supported orientations
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }
    
    @end
    
    when I run this in the iOS simulator and click the equals button I get the following exception:

    'NSInvalidArgumentException', reason: '-[__NSCFString appendString:]: nil argument'

    for the following line of code

    Code:
    
        [displayString appendString: [myCalculator.accumulator convertToString]];
    
    
    Ok, so I thought "The myCalculator" reference must not be instantiated and is set to nil.


    So, I instantiate it in "clickEquals" (I get a warning that says I'm masking my instance variable (though Xcode won't let me instantiate that one)) and it works. It clears up the exception.

    BUT there is a bit of a scope problem.

    So I need some help.

    :)
     
  2. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #2
    It always helps if you can be as specific as possible about the resources you are using. For books: title, author, edition. In this case, you might as well provide the chapter number / page numbers, as well.
     
  3. ArtOfWarfare macrumors G3

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #3
    Your description of the code doesn't match what's actually in the code...

    Here's what you described:
    But that's not what's in the code, because your viewDidLoad method instantiates it:

    Then you go on to say this:
    This doesn't quite match what you actually have posted in the code, either (because the line is commented out.)
    As far as I can tell, the code you've posted looks perfectly alright (I didn't actually try copying and pasting it into Xcode though,) but because your description of the code doesn't match what you actually posted for code, I wonder if maybe you have a mistake in Xcode that was lost when you copied the code over to the forums?
     
  4. AlbuquerqueApac thread starter macrumors member

    Joined:
    Jan 13, 2012
    #4

    The book is Stephen G. Kochan's Programming in Objective-C (4th edition) and the excercise begins on 464 and continues for the remainder of the book.

    ----------

    ArtofWar:

    yeah, I commented out the line because defining it locally like that serves no purpose. Sure, it doesn't throw an exception, but none of the other methods can access it.

    A good starting point would be:

    Can I instantiate the myCalculator globally in the implementation file? For some reason, Xcode only allows me to create it as a nil pointer.
     
  5. AlbuquerqueApac thread starter macrumors member

    Joined:
    Jan 13, 2012
    #5
    Ok, so I have confirmed what I thought to be the case:

    Code:
    
    
    @implementation ViewController 
    
    
    
    
    //instance variables (though I think I would of set these up as object properties
    
    {
    char op;
    int currentNumber;
    BOOL firstOperand, isNumerator;
    
    Calculator *myCalculator; 
    
    
    
    NSMutableString *displayString;
    
    }
    
    @synthesize display;
    
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Release any cached data, images, etc that aren't in use.
    }
    
    #pragma mark - View lifecycle
    
    - (void)viewDidLoad
    {
        //overrided the initiall loading
        
        firstOperand = YES;
        isNumerator = YES;
    
       displayString = [NSMutableString stringWithCapacity:40];
        
       Calculator *myCalculator = [[Calculator alloc]init];
    }
    
    -(void)processDigit:(int)digit
    {
        currentNumber = currentNumber * 10 + digit;
        
        [displayString appendString: [NSString stringWithFormat: @"%i", digit]];
        
        display.text = displayString;
        
    }
    
    - (IBAction)clickDigit:(UIButton *)sender
    {
        
        int digit = sender.tag; 
        
        [self processDigit:digit]; 
        
    }
    
    -(void) processOp:(char)theOp
    {
        NSString *opString;
        
        op = theOp;
        
        switch (theOp) { 
            case '+': 
                opString = @"+";
                break;
            case '-':
                opString = @"-";
                break;
            case '*':
                opString = @"x";
                break;
            case '/':
                opString = @"/";
                break;
                
        }
    
        [self storeFracPArt];
        
        firstOperand = NO;
        isNumerator = YES; 
        
        [displayString appendString: opString];
        
        display.text = displayString; 
        
    }
    
    -(void) storeFracPArt
    {
        if (firstOperand) { 
            if (isNumerator) {
                myCalculator.operand1.numerator = currentNumber;
                myCalculator.operand1.denominator = 1;}
            else 
                myCalculator.operand1.denominator = currentNumber; 
            }
        else if (isNumerator) { 
            myCalculator.operand2.numerator = currentNumber;
            myCalculator.operand2.denominator= 1;
            }
        else
        { 
            myCalculator.operand2.denominator = currentNumber;
            firstOperand = YES; 
        }
        currentNumber = 0;
        
    }
     
    -(IBAction)clickOver
    {
        [self storeFracPArt];
        isNumerator = NO;
        [displayString appendString: @"|"];
        display.text = displayString;
    }
    
    //arithmetic operations
    
    -(IBAction) clickPlus
    {
        [self processOp: '+'];
        
    }
    
    -(IBAction)clickMinus
    {
        [self processOp: '-'];
        
    }
    
    -(IBAction)clickMultiply
    {
        [self processOp: '*'];
        
    }
    
    -(IBAction)clickDivide
    {
        [self processOp: '/'];
        
    }
    
    //misc buttons 
    
    -(IBAction)clickEquals
    {
        if ( firstOperand == NO) {
            
            NSString *calc = [NSString stringWithFormat:@"%@", myCalculator];
                              
            display.text=calc;
            
            
            
             
           
            /*
            
            [self storeFracPArt];
            [myCalculator performOperation: op];
            [displayString appendString: @"="];
            
            [displayString appendString: [myCalculator.accumulator convertToString]];
            
            display.text=displayString;
            
            
            currentNumber=0;
            isNumerator=YES;
            firstOperand=YES;
           [displayString setString:@""];
            
        
            */
            
            
            
        }
        
        
    }
    
    -(IBAction)clickClear
    {
        isNumerator= YES;
        firstOperand = YES;
        currentNumber = 0;
        [myCalculator clear];
        [displayString setString:@""];
        display.text=displayString;
        
        
    }
    
    
    
    
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
    }
    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
    	[super viewWillDisappear:animated];
    }
    
    - (void)viewDidDisappear:(BOOL)animated
    {
    	[super viewDidDisappear:animated];
    }
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        // Return YES for supported orientations
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }
    
    @end
    
    
    Ok, so after making these changes, I hit equals and.....

    I get : (NULL)

    So.... I figured out my problem, just need to fix it.

    :S
     
  6. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #6
    You sure the last line of your viewDidLoad method (highlighted in red above) matches that from the book?
     
  7. AlbuquerqueApac thread starter macrumors member

    Joined:
    Jan 13, 2012
    #7
    haha! That was it! THANK YOU!

    I guess writing

    Code:
    
    Calculator *myCalculator = [[ Calculator alloc] init];
    
    instead of
    
    (no pointer or class declaration )
    
    myCalculator = [[ Calculator alloc] init];
    
    
    actually created a separate (or maybe masked) the instance variable I declared

    Code:
    
    Calculator *myCalculator; 
    
    

    THANK YOU GUYS!
     
  8. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #8
    It actually created a separate, local-scope (to the viewDidLoad method) variable that, because it had the same name, masked your instance variable (hence the warning). I think it's important for you to understand this and suggest you go over your code and the fundamentals and be sure you do.
     
  9. AlbuquerqueApac, May 9, 2012
    Last edited: May 9, 2012

    AlbuquerqueApac thread starter macrumors member

    Joined:
    Jan 13, 2012
    #9
    I understand. I was masking my variable.

    I do have a question. Can you instantiate the myCalculator object at the instance variable declaration? Or must I do it as the view loads?
     
  10. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #10
    You can't instantiate objects in a declaration, since it's just a declaration, not any kind of implementation (i.e. no code runs there). And no, you don't need to do it in your viewDidLoad. You just should do it before you first need to access it. It's pretty normal for viewDidLoad to be the place for this (as long as you are de-instantiating it in your viewDidUnload), but it is also quite common to see it done in the init method (or any of its variants).
     

Share This Page