Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

Storyboard Segue problem with plist.

greeneye82greeneye82 Posts: 20Registered Users
edited June 2012 in iPhone SDK Development
I have my data in a plist, which is a list of cities names alphabetized, it also contains a phone number which is to be pushed to the info view and displayed,when the user selects a row (city name) in the table view. I've gone from using a NSMutable array to now a plist to hold my data, now my segue isn't working properly. The build succeeds in the simulator but throws an error when you click on a table cell. Any thoughts as to why this isn't working properly? I'm thinking its a variable either in my cellForRowAtIndex.. or in my prepareForSegue method.

#import \"CityListTableViewController.h\"

@interface CityListTableViewController ()

@end

@implementation CityListTableViewController

@synthesize cities, sections;

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

//ensure this is the Segue which is leading to the info view
if ([segue.identifier isEqualToString:@\"ShowInfo\"])
{
//now setup info controller so it can function...
//get the info instance
InfoViewController *ivc = [segue destinationViewController];
//get the selected row and city name from it
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
//inform the info view of the selected city
int row = [path row];
City *c = [cities objectAtIndex:row];
[ivc setCurrentCity:[cities objectAtIndex:path.row]];
ivc.currentCity = c;
}

}


- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}


- (void)viewDidLoad {



self.cities = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@\"cities\" ofType:@\"plist\"]];
self.sections = [[NSMutableDictionary alloc] init];

BOOL found;

// Loop through the cities and create our keys
for (NSDictionary *city in self.cities)
{
NSString *c = [[city objectForKey:@\"city\"] substringToIndex:1];

found = NO;

for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:c])
{
found = YES;
}
}

if (!found)
{
[self.sections setValue:[[NSMutableArray alloc] init] forKey:c];
}
}

// Loop again and sort the cities into their respective keys
for (NSDictionary *city in self.cities)
{
[[self.sections objectForKey:[[city objectForKey:@\"city\"] substringToIndex:1]] addObject:city];
}

// Sort each section array
for (NSString *key in [self.sections allKeys])
{
[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@\"city\" ascending:YES]]];
}

[super viewDidLoad];
}


- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - Table view data source


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.sections allKeys] count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section]] count];
}


- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return [[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}


// Customize the appearance of table view cells.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *CellIdentifier = @\"DeptCell\";

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

NSDictionary *current = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];


cell.textLabel.text = [current objectForKey:@\"city\"];


return cell;
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];

}
@end
Post edited by greeneye82 on

Replies

  • Duncan CDuncan C Posts: 8,147Tutorial Authors, Registered Users
    edited June 2012
    greeneye82;437415 said:
    I have my data in a plist, which is a list of cities names alphabetized, it also contains a phone number which is to be pushed to the info view and displayed,when the user selects a row (city name) in the table view. I've gone from using a NSMutable array to now a plist to hold my data, now my segue isn't working properly. The build succeeds in the simulator but throws an error when you click on a table cell. Any thoughts as to why this isn't working properly? I'm thinking its a variable either in my cellForRowAtIndex.. or in my prepareForSegue method.

    #import \"CityListTableViewController.h\"

    @interface CityListTableViewController ()

    @end

    @implementation CityListTableViewController

    @synthesize cities, sections;

    -(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    //ensure this is the Segue which is leading to the info view
    if ([segue.identifier isEqualToString:@\"ShowInfo\"])
    {
    //now setup info controller so it can function...
    //get the info instance
    InfoViewController *ivc = [segue destinationViewController];
    //get the selected row and city name from it
    NSIndexPath *path = [self.tableView indexPathForSelectedRow];
    //inform the info view of the selected city
    int row = [path row];
    City *c = [cities objectAtIndex:row];
    [ivc setCurrentCity:[cities objectAtIndex:path.row]];
    ivc.currentCity = c;
    }

    }


    - (id)initWithStyle:(UITableViewStyle)style
    {
    self = [super initWithStyle:style];
    if (self) {
    // Custom initialization
    }
    return self;
    }


    - (void)viewDidLoad {



    self.cities = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@\"cities\" ofType:@\"plist\"]];
    self.sections = [[NSMutableDictionary alloc] init];

    BOOL found;

    // Loop through the cities and create our keys
    for (NSDictionary *city in self.cities)
    {
    NSString *c = [[city objectForKey:@\"city\"] substringToIndex:1];

    found = NO;

    for (NSString *str in [self.sections allKeys])
    {
    if ([str isEqualToString:c])
    {
    found = YES;
    }
    }

    if (!found)
    {
    [self.sections setValue:[[NSMutableArray alloc] init] forKey:c];
    }
    }

    // Loop again and sort the cities into their respective keys
    for (NSDictionary *city in self.cities)
    {
    [[self.sections objectForKey:[[city objectForKey:@\"city\"] substringToIndex:1]] addObject:city];
    }

    // Sort each section array
    for (NSString *key in [self.sections allKeys])
    {
    [[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@\"city\" ascending:YES]]];
    }

    [super viewDidLoad];
    }


    - (void)viewDidUnload
    {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    }

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }

    #pragma mark - Table view data source


    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
    return [[self.sections allKeys] count];
    }

    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
    return [[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section];
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    return [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section]] count];
    }


    - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
    {
    return [[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    }


    // Customize the appearance of table view cells.

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {

    static NSString *CellIdentifier = @\"DeptCell\";

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

    NSDictionary *current = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];


    cell.textLabel.text = [current objectForKey:@\"city\"];


    return cell;
    }


    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    }
    @end

    What's the error, and on what line?

    Off the top of my head, are you assuming that when you write a mutable array to a plist, it will come back as a mutable array? It won't. Array objects that you save to a plist or NSArchive are read back as immutable object. You have to use the mutableCopy method to create a mutable copy out of the immutable version you read from the plist.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • greeneye82greeneye82 Posts: 20Registered Users
    edited June 2012
    Duncan C;437424 said:
    What's the error, and on what line?

    Off the top of my head, are you assuming that when you write a mutable array to a plist, it will come back as a mutable array? It won't. Array objects that you save to a plist or NSArchive are read back as immutable object. You have to use the mutableCopy method to create a mutable copy out of the immutable version you read from the plist.
    I'll take a look at the mutableCopy method. Thank you. This is the error I am getting:
    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary city]: unrecognized selector sent to instance 0x68736c0'
  • Duncan CDuncan C Posts: 8,147Tutorial Authors, Registered Users
    edited June 2012
    greeneye82;437480 said:
    I'll take a look at the mutableCopy method. Thank you. This is the error I am getting:
    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary city]: unrecognized selector sent to instance 0x68736c0'
    That doesn't sound like a mutable/immutable problem.

    Which line is throwing the error?
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • greeneye82greeneye82 Posts: 20Registered Users
    edited June 2012
    Duncan C;437553 said:
    That doesn't sound like a mutable/immutable problem.

    Which line is throwing the error?
    Still a learning process here, so it forced me to learn more about the debugger. I determined that the error is caused by a line in my infoViewController, under viewDidLoad, on the city title.
    - (void)viewDidLoad
    {
    [super viewDidLoad];

    //this sets the title bar to the currently selected city, and also displays the current phone number for the selected city.
    [self setTitle:[currentCity cityname]];


    [phoneNumberLabel setText:[currentCity phone]];

    }


    Basically, everything was working fine when I used a model-object style of holding my data in NSMutableArray. Now that I am using a plist this seems to have changed everything. This code above does not work now that I am using a plist. Am I way off here?
  • Duncan CDuncan C Posts: 8,147Tutorial Authors, Registered Users
    edited June 2012
    greeneye82;437638 said:
    Still a learning process here, so it forced me to learn more about the debugger. I determined that the error is caused by a line in my infoViewController, under viewDidLoad, on the city title.
    - (void)viewDidLoad
    {
    [super viewDidLoad];

    //this sets the title bar to the currently selected city, and also displays the current phone number for the selected city.
    [self setTitle:[currentCity cityname]];


    [phoneNumberLabel setText:[currentCity phone]];

    }


    Basically, everything was working fine when I used a model-object style of holding my data in NSMutableArray. Now that I am using a plist this seems to have changed everything. This code above does not work now that I am using a plist. Am I way off here?
    You can continue to use identical code, and continue to hold your data in a mutable array. Just read the data from your plist when you start the program, and convert that plist into a mutable array using the mutableCopy method I mentioned previously. The rest of your code should not change at all.

    The error you reported does not make sense with the code that you posted. The error says that you are sending a message "city" to a dictionary object. The code you posted in your viewDidLoad method does not send a "city" message to anything. I see you sending the message "cityName" to "currentCity". if currentCity is a dictionary object, that code would crash, but I would expect it to show an error about the object not responding to "cityName".
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
Sign In or Register to comment.