1 damn error (noob warning)

Discussion in 'iOS Programming' started by ryans79, Jun 5, 2009.

  1. ryans79 macrumors regular

    Joined:
    Apr 12, 2009
    #1
    Hello,
    I am a noob and am finding it hard to know where exactly the damn error is.

    Here are both my files, the first is the .h and the second.m
    the error i am getting is:
    error: synthesized property 'column5' must be named the same as a compatible ivar or must explicitly name an ivar
    I have no idea what that means :mad:

    .h file
    Code:
    #import <UIKit/UIKit.h>
    
    
    @interface CustomPickerViewController : UIViewController 
    <UIPickerViewDataSource, UIPickerViewDelegate>
    {
    
    	IBOutlet UIPickerView *picker;
    	IBOutlet UILabel *winLabel;
    	
    	NSArray *column1;
    	NSArray *column2;
    	NSArray *column3;
    	NSArray *column4;	
    }	NSArray *column5;
    
    @property (nonatomic, retain) UIPickerView *picker;
    @property (nonatomic, retain) UILabel *winLabel;
    @property (nonatomic,retain ) NSArray *column1;
    @property (nonatomic,retain ) NSArray *column2;
    @property (nonatomic,retain ) NSArray *column3;
    @property (nonatomic,retain ) NSArray *column4;
    @property (nonatomic,retain ) NSArray *column5;
    
    -(IBAction) spin;
    
    @end
    

    .m file
    Code:
    #import "CustomPickerViewController.h"
    
    
    @implementation CustomPickerViewController
    
    @synthesize picker;
    @synthesize winLabel;
    @synthesize column1;
    @synthesize column2;
    @synthesize column3;
    @synthesize column4;
    @synthesize column5;
    
    
    // The designated initializer. Override to perform setup that is required before the view is loaded.
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
            // Custom initialization
        }
        return self;
    }
    
    - (IBAction)spin 
    {
    	BOOL win = NO;
    	int numInRow =1;
    	int lastVal =-1;
    
    	for(int i = 0; i<5; i++)
    	{
    		int newValue = random() % [self.column1 count];
    		
    		if(newValue == lastVal)
    		{
    			numInRow ++;
    		}else
    		{numInRow = 1;}
    		
    		lastVal = newValue;
    		
    		[picker selectRow:newValue inComponent:i animated:YES];
    		[picker reloadComponent:i];
    		
    		if(numInRow >=3){win=YES;}
    	}
    	
    	if (win){winLabel.text = @"Win!";}else{winLabel.text = @"";}
    }
    
    
    /*
    // Implement loadView to create a view hierarchy programmatically, without using a nib.
    - (void)loadView {
    }
    */
    
    
    // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
    - (void)viewDidLoad 
    {
    	
    	UIImage *seven = [UIImage imageNamed:@"seven.png"];
    	UIImage *bar = [UIImage imageNamed:@"bar.png"];	
    	UIImage *crown = [UIImage imageNamed:@"crown.png"];
    	UIImage *cherry = [UIImage imageNamed:@"cherry.png"];	
    	UIImage *lemon = [UIImage imageNamed:@"lemon.png"];	
    	UIImage *apple = [UIImage imageNamed:@"apple.png"];	
    	
    	for(int i=1; i <=5; i++)
    	{
    		UIImageView *sevenView = [[UIImageView alloc] initWithImage:seven];
    		UIImageView *barView = [[UIImageView alloc] initWithImage:bar];
    		UIImageView *crownView = [[UIImageView alloc] initWithImage:crown];
    		UIImageView *cherryView = [[UIImageView alloc] initWithImage:cherry];
    		UIImageView *lemonView = [[UIImageView alloc] initWithImage:lemon];
    		UIImageView *appleView = [[UIImageView alloc] initWithImage:apple];
    
    		NSArray *imageViewArray = [[NSArray alloc]
    					initWithObjects:sevenView, barView,crownView,cherryView,lemonView,appleView,nil];
    		NSString *fieldName = [[NSString alloc] initWithFormat:@"column %d, i"];
    		[self setValue:imageViewArray forKey:fieldName];
    		[fieldName release];
    		[imageViewArray release];
    		
    		[sevenView release];
    		[barView release];
    		[crownView release];
    		[cherryView release];
    		[lemonView release];
    		[appleView release];
    		
    	}
    
      //  [super viewDidLoad];
    
    	srandom(time(NULL));
    }
    
    
    
    // Override to allow orientations other than the default portrait orientation.
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
        // Release anything that's not essential, such as cached data
    }
    
    
    - (void)dealloc {
    	[picker release];
    	[winLabel release];
    	[column1 release];
    	[column2 release];
    	[column3 release];
    	[column4 release];
    	[column5 release];
    	
        [super dealloc];
    }
    
    #pragma mark -
    #pragma mark Picker Data Source Methods
    
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
    {return 5;}
    
    -(NSInteger)pickerView:(UIPickerView *)pickerView
    numberOfRowsInComponent:(NSInteger)component 
    {
    	return [self.column1 count];
    
    }
    
    #pragma mark Picker Delegate Methods
    
    - (UIView *)pickerView:(UIPickerView *)pickerView
    			viewForRow:(NSInteger)row
    		  forComponent:(NSInteger)component 
    		   reusingView:(UIView *)view
    {
    NSString *arrayName = [[NSString alloc] initWithFormat:
    					   @"COLUMN %d", component +1];
    	NSArray *array = [self valueForKey:arrayName];
    	return [array objectAtIndex:row];
    }
    
    @end
    

    the error shows up right at the bottom ( after @end )

    °°
     
  2. mccannmarc macrumors 6502

    mccannmarc

    Joined:
    Aug 15, 2008
    Location:
    Manchester, UK
    #2
    You havent put the IBOutlet keyword in the @property declarations for the UIPickerView and the UILabel in the header file it should look like:-

    Code:
    #import <UIKit/UIKit.h>
    
    
    @interface CustomPickerViewController : UIViewController 
    <UIPickerViewDataSource, UIPickerViewDelegate>
    {
    
    	IBOutlet UIPickerView *picker;
    	IBOutlet UILabel *winLabel;
    	
    	NSArray *column1;
    	NSArray *column2;
    	NSArray *column3;
    	NSArray *column4;	
    }	NSArray *column5;
    
    @property (nonatomic, retain) IBOutlet UIPickerView *picker;
    @property (nonatomic, retain) IBOutlet UILabel *winLabel;
    @property (nonatomic,retain ) NSArray *column1;
    @property (nonatomic,retain ) NSArray *column2;
    @property (nonatomic,retain ) NSArray *column3;
    @property (nonatomic,retain ) NSArray *column4;
    @property (nonatomic,retain ) NSArray *column5;
    
    -(IBAction) spin;
    
    @end
    
     
  3. Darkroom Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #3
    you aren't providing an instance variable for column5. look closely.

    you have this:
    Code:
    @interface UntitledViewController : UIViewController 
    <UIPickerViewDataSource, UIPickerViewDelegate>
    {
    
    	IBOutlet UIPickerView *picker;
    	IBOutlet UILabel *winLabel;
    	
    	NSArray *column1;
    	NSArray *column2;
    	NSArray *column3;
    	NSArray *column4;	
    [B][COLOR="Red"]}[/COLOR][/B]	NSArray *column5;
    
    that pesky brace is closing off your declairations before column5... move it after you declare column5 and you'll be good.
     
  4. ryans79 thread starter macrumors regular

    Joined:
    Apr 12, 2009
    #4
    Got it!

    Messed up on the curly braces...

    Thanks guys!

    EDIT: The book has come online examples that mirror the examples in the book, but i prefer doing it "manually" as i think it helps to get it stuck in my head, and also good practice for small error correction that crop up... but this one baffled me because it was giving me the error in the M file while the problem was in the H
     
  5. Darkroom Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #5
    having both is neither common nor necessary. IBOutlet is only used for Interface Builder. it returns nothing in code so wouldn't cause any errors.

    apple suggests writing it in the @property lines (for some unknown reason), but one or the other is fine. i think it's more common for them to be written in the instance variables as they have been before Obj-C 2.0. either or is fine.
     
  6. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #6
    Few comments:

    Darkroom, good eye. That was some obfuscated code right there ;-)

    ryan, GCC does have some obscure error messages. You just have to learn what they mean. This one is somewhat clear however.

    Your property consists of the @property and @synthesize directives. The error message specifically says that the column5 property is defective. The compatible ivar it refers to is the column5 instance variable that was not properly declared. What you may not know is that you can have a property that refers to an ivar with a different name like this:

    @property NSArray * importantColumn;

    @synthesize importantColumn = column5;

    where this new property, importantColumn, will get/set the ivar column5. That is what the error message is referring to when it says 'or must explicityly name an ivar'.

    mccannmarc, you were wrong about the cause of this error but partly right about the right way to write this code. ryan, you should put the IBOutlet token on your properties. That can be in addition to or in place of putting that token on your ivars but it really should go on the property. There are some obscure and hard to find bugs that can happen if you don't. mccannmarc, you might find it interesting to look up the declaration of IBOutlet in the headers to see why missing the IBOutlet token or having it in an odd place won't cause compiler errors (although could give IB a headache).
     
  7. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #7
    The keypath that is used to set the outlet when the nib is loaded is parsed by IB based on the IBOutlet token. The outlet can be set whether the property is present or not. If the property and the ivar have different names then it's essential that the IBOutlet token is on the property because the wrong keypath will be saved. If the IBOutlet token isn't on the property then the ivar will be set directly, which may not be what you want.

    I ran into this problem and it was a bear to track down. I always name my ivars with a leading m wart and that caused me a big problem until I understood how this whole process works.
     
  8. BlackWolf macrumors regular

    Joined:
    Apr 9, 2009
    #8
    it will do this a lot btw, because the .h file is never executed on his own. it is imported in the .m file via #import and by that considered a single file.
     
  9. mccannmarc macrumors 6502

    mccannmarc

    Joined:
    Aug 15, 2008
    Location:
    Manchester, UK
    #9
    I've always just put it in both without thinking really. I'm not a big user of IB anyway so its rare I've ever even used it. Thanks for clearing that up, you learn something new every day
     
  10. ryans79 thread starter macrumors regular

    Joined:
    Apr 12, 2009
    #10
    Yep, I got that, but i was barking up the wrong tree, i thought maybe i had a spelling problem somewhere or missing semicolon etc
    the other thing that threw me was it mentioned only column5 and not the others that were outside the curly brace... had it told me column 1-5 were screwy i would have tracked that down i'm sure.


    Thanks, I have not come to this yet in my book, i guess further chapters.
    I'm a bit confused here :eek: can you give me an example and a bit of a larger explanation please?

    Thanks!
     
  11. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #11
    Do this:

    Code:
    IBOutlet UIPickerView *picker;
    
    @property (nonatomic, retain) IBOutlet UIPickerView *picker;
    
    I explained why above but to make it a little simpler IB parses the header file looking for the IBOutlet token. It saves the name, 'picker', in this case. The name, as in the text string, is used when the nib is loaded to set the outlet's value. It is possible to have certain kinds of errors, like a spelling error, or others that are silent if you don't put the IBOutlet token on the property. No error from IB or when the nib loads, but things go wrong later.

    I usually only have the IBOutlet token on the property but I think having it on both the property and the ivar is OK also. Having it on just the ivar will work in many cases but might cause silent errors.
     

Share This Page