Search code examples
objective-cios6

unrecognized selector sent to instance while trying to add an object to a mutable array


I'm following the "Your Second iOS App" and I decided to play with the code to understand Objective C well...

What I'm trying to do is simply adding an object to a mutable array in a class. Here are the classes:

BirdSighting.h

#import <Foundation/Foundation.h>

@interface BirdSighting : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *location;
@property (nonatomic, copy) NSDate *date;

-(id) initWithName: (NSString *) name location:(NSString *) location date:(NSDate *) date;
@end

BirdSighting.m

#import "BirdSighting.h"

@implementation BirdSighting
-(id) initWithName:(NSString *)name location:(NSString *)location date:(NSDate *)date
{
    self = [super init];

    if(self) {
        _name = name;
        _location = location;
        _date = date;

        return self;
    }

    return nil;
}

@end

BirdSightingDataController.h

#import <Foundation/Foundation.h>
@class BirdSighting;

@interface BirdSightingDataController : NSObject
@property (nonatomic, copy) NSMutableArray *masterBirdSightingList;

- (NSUInteger) countOfList;
- (BirdSighting *) objectInListAtIndex: (NSUInteger) theIndex;
- (void) addBirdSightingWithSighting: (BirdSighting *) sighting;
@end

BirdSightingDataController.m

#import "BirdSightingDataController.h"

@implementation BirdSightingDataController
- (id) init {
    if(self = [super init]) {
        NSMutableArray *sightingList = [[NSMutableArray alloc] init];
        self.masterBirdSightingList = sightingList;
        return self;
    }

    return nil;
}

-(NSUInteger) countOfList 
{
    return [self.masterBirdSightingList count];
}

- (BirdSighting *) objectInListAtIndex: (NSUInteger) theIndex
{
    return [self.masterBirdSightingList objectAtIndex:theIndex];
}

- (void) addBirdSightingWithSighting: (BirdSighting *) sighting
{
    [self.masterBirdSightingList addObject:sighting];
}
@end

And this is where I'm trying to add a BirdSighting instance to the mutable array:

#import "BirdsMasterViewController.h"
#import "BirdsDetailViewController.h"

#import "BirdSightingDataController.h"
#import "BirdSighting.h"

@implementation BirdsMasterViewController

- (void)awakeFromNib
{
    [super awakeFromNib];

    BirdSightingDataController *dataController = [[BirdSightingDataController alloc] init];

    NSDate *date = [NSDate date];
    BirdSighting *sighting = [[[BirdSighting alloc] init] initWithName:@"Ebabil" location:@"Ankara" date: date];

    [dataController addBirdSightingWithSighting: sighting];
    NSLog(@"dataController: %@", dataController.masterBirdSightingList);

    self.dataController = dataController;

}
..........
@end

It throws NSInvalidArgumentException in BirdSightingDataController addBirdSightingWithSighting method...

What am I doing wrong?

This is the full debug output: 2012-11-26 01:22:38.495 BirdWatching[4597:c07] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x71899d0 2012-11-26 01:22:38.496 BirdWatching[4597:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x71899d0'


Solution

  • This line:

    BirdSighting *sighting = [[[BirdSighting alloc] init] initWithName:@"Ebabil" location:@"Ankara" date: date];
    

    should be:

    BirdSighting *sighting = [[BirdSighting alloc] initWithName:@"Ebabil" location:@"Ankara" date: date];
    

    You can't call two initializers.

    Update:

    Based on the complete error message I now see the problem. The NSMutableArray you think you have for the property is really an NSArray. This is caused by defining the property with copy.

    When you define copy for a property, it makes an immutable copy of the object. So when you assign your NSMutableArray, an immutable copy is made and then assigned to the instance variable. So you end up assigning an NSArray, not an NSMutableArray.

    A fix is to change the property definition from:

    @property (nonatomic, copy) NSMutableArray *masterBirdSightingList;
    

    to:

    @property (nonatomic, strong) NSMutableArray *masterBirdSightingList;