2
votes

I know there have been a ton of questions about the same thing, but so far I haven't been able to apply any solutions to my problem. And I still haven't figured out how to use Instruments.

I'm taking a basic tutorial for an iPhone app and just trying to tweak it slightly (I am new to Objective C). I want it to read from a plist with an array of dicts instead of an array of strings. The table initially displays the data correctly. However whenever I scroll the table up (and off the screen), I am getting Unrecognized Selector exceptions. Just populating employees with NSStrings works fine. I am lost.

Relevant portions of the ViewController:

@interface RootViewController : UITableViewController {

NSMutableArray *employees_;
}

@property (nonatomic, retain) NSMutableArray *employees;
@end

and

@implementation RootViewController

@synthesize employees=employees_;


- (void)viewDidLoad
{
 [super viewDidLoad];

 NSString *path = [[NSBundle mainBundle] pathForResource:@"Employees" ofType:@"plist"];

 NSMutableArray *empArray = [[NSMutableArray alloc] initWithContentsOfFile:path];

 employees_ = [empArray valueForKey:@"name"];
 [empArray release];

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}

// Configure the cell.

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [self.employees objectAtIndex:indexPath.row];//this is where it errors

return cell;
}
- (void)dealloc
{
 [employees_ release];
 [super dealloc];
}

@end

and plist:

array
      dict
        key name /key
        string Employee One /string
        key id /key
        string T1234 /string 
      /dict
      dict
        key name /key
        string Employee Two /string
        key id /key
        string T5678 /string 
     /dict
/array

Error that I received:

2011-10-18 20:02:44.313 MyApp[65148:bc03] -[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x689a050
2011-10-18 20:02:44.316 MyApp[65148:bc03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x689a050'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00dc25a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00f16313 objc_exception_throw + 44
    2   CoreFoundation                      0x00dc40bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x00d33966 ___forwarding___ + 966
    4   CoreFoundation                      0x00d33522 _CF_forwarding_prep_0 + 50
    5   MyApp                    0x00002a96 -[RootViewController tableView:cellForRowAtIndexPath:] + 326
    6   UIKit                               0x00089b98 -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:] + 634
    7   UIKit                               0x0007f4cc -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] + 75
    8   UIKit                               0x000948cc -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:] + 1561
    9   UIKit                               0x0008c90c -[UITableView layoutSubviews] + 242
    10  QuartzCore                          0x016aca5a -[CALayer layoutSublayers] + 181
    11  QuartzCore                          0x016aeddc CALayerLayoutIfNeeded + 220
    12  QuartzCore                          0x016540b4 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 310
    13  QuartzCore                          0x01655294 _ZN2CA11Transaction6commitEv + 292
    14  QuartzCore                          0x0165546d _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
    15  CoreFoundation                      0x00da389b __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
    16  CoreFoundation                      0x00d386e7 __CFRunLoopDoObservers + 295
    17  CoreFoundation                      0x00d011d7 __CFRunLoopRun + 1575
    18  CoreFoundation                      0x00d00840 CFRunLoopRunSpecific + 208
    19  CoreFoundation                      0x00d00761 CFRunLoopRunInMode + 97
    20  GraphicsServices                    0x00ffa1c4 GSEventRunModal + 217
    21  GraphicsServices                    0x00ffa289 GSEventRun + 115
    22  UIKit                               0x00022c93 UIApplicationMain + 1160
    23  MyApp                    0x00002249 main + 121
    24  MyApp                    0x000021c5 start + 53
)
terminate called throwing an exceptionCurrent language:  auto; currently objective-c
(gdb) 
2

2 Answers

3
votes

There are two potential problems:

  1. You need to make sure the call to employees_ = [empArray valueForKey:@"name"] is actually returning a NSArray

  2. Once one is ruled out, and assuming you are not using ARC, your employees_ ivar is getting released before the table view gets a chance to configure itself. Try

    employees_ = [[empArray valueForKey:@"name"] retain];

And then release employees_ in your viewDidUnload & dealloc methods.

Hard to tell it from the stack as it does say your ivar is a NSCFString but it could be just because it is referencing an invalid/garbage memory address. Based on your plist description though, the likely cause on on point #1.

0
votes

-[NSCFString objectAtIndex:]: unrecognized selector

This means you tried to send the selector (i.e. call the method) objectAtIndex: on an instance of class NSCFString (which is the same as NSString). ("Next Step / Core Foundation String")

You can't do that.

Since you only are calling objectAtIndex: in one place in your above code, it's easy to see where the problem is. (Besides which in your debugger you should be able to see what line it happens on.) You're calling [self.employees objectAtIndex:...]. Obviously you expect self.employees to be an array, but it is a string instead. I don't really know about plist processing, so figuring out why employees got a string and how to make it get an array instead is up to you.