Question

I have this arquivo.plist below.
I looked at Apple's documentation, but I could not find how to make the listing look and I hope someone can help me.


In the first UITableView, I make a list of names present in arquivo.plist using the following code and loading the following method below.

What I'm trying to do is: When the user clicks on a tableView name, he is taken to a second screen with a new tableView that will display the "frams" of that user.

The problem is that the code I'm using to select the "frams" is the same code that I am using for listing the names on the first screen, but it is not working, because each user has only one name, but it has several "frams".
When I try to implement this, I can even assemble the array with the "frams" and pass using segue (i'll show the array with an NSLog), but this array can not be displayed as a tableView for an error that Xcode is giving me:

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary length]: unrecognized selector sent to instance 0x8b87a60'

The code from the fist view (ViewController.m) is below the contatos.plist

I hope you understand what I'm trying to do and bring me a light! Thank you all!

a screenshot of the .plist file is bellow:

http://img268.imageshack.us/img268/7356/jl26.png

For reference and for you to better understand the issue, when the user clicks on a table name, an array is generated with "frams" this patient (patients have on average 3 frams each). The Array NSLog that it should be passed to the other page and comport a new table generates the following text:

 12/12/2013 16:10:13.513 rer [24251:70 b] (
{
    1 = 11;
    2 = 12;
    3 = 13;
}

I think that's where the problem lies, because this method of Array can not be implemented in a TableView, so I look a light of a better way to mount this array and select frams when I click a patient

So here is my ViewController.m:

#import "ViewController.h"
#import "Contato.h"
#import "perfilViewController.h"

@interface ViewController ()
-(void) loadContacts;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self loadContacts];
}

-(void) loadContacts
{
    NSString *plistCaminho = [[NSBundle mainBundle] pathForResource:@"contatos"
                                                             ofType:@"plist"];
    NSDictionary *pl = [NSDictionary dictionaryWithContentsOfFile:plistCaminho];
    NSArray *dados = [pl valueForKey:@"contatos"];

    contatos = [[NSMutableArray alloc] init];

    for (NSDictionary *item in dados) {
        NSString *nome = [item valueForKey:@"nome"];
        NSString *telefone = [item valueForKey:@"telefone"];
        NSString *fram = [item valueForKey:@"fram"];

        Contato *c = [[Contato alloc] initWithNome:nome andTelefone:telefone andFram:fram];
        [contatos addObject:c];
    }
}

#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return contatos.count;
}

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CelulaContatoCacheID = @"CelulaContatoCacheID";
    UITableViewCell *cell = [self.tabelaContatos dequeueReusableCellWithIdentifier:CelulaContatoCacheID];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:CelulaContatoCacheID];
    }
    Contato *contato = [contatos objectAtIndex:indexPath.row];
    cell.textLabel.text = contato.nome;
    return cell;
}

#pragma mark -
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Contato *contato = [contatos objectAtIndex:indexPath.row];
    NSString *msg = [NSString stringWithFormat:@"Fram:%@",contato.fram];

    fran = [[NSMutableArray alloc] init];
    fran = [NSMutableArray arrayWithObject:contato.telefone];

    NSLog(@"finalmente eu consegui essa porra!!!%@", fran);

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Contato"
                                                    message:msg
                                                   delegate:nil
                                          cancelButtonTitle:@"OK" 
                                          otherButtonTitles:nil];
    [alert show];
    [self.tabelaContatos deselectRowAtIndexPath:indexPath animated:YES];
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"vai"]) {
        NSIndexPath *indexPath = [self.tabelaContatos indexPathForSelectedRow];
        perfilViewController *destViewController = segue.destinationViewController;
        Contato *contato = [contatos objectAtIndex:indexPath.row];

        fran = [[NSMutableArray alloc] init];
        fran = [NSMutableArray arrayWithObject:contato.fram];
        destViewController.frans = fran;
        NSLog(@"%@%@", fran, destViewController.frans);
    }
}
@end
Was it helpful?

Solution

I'd firstly do:

//declare NSDictionary *pl; in the ViewController.h
pl = [NSDictionary dictionaryWithContentsOfFile:plistCaminho];

Then to display Names, i'd simply use the dictionary as such:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[pl objectForKey:@"contatos"] count];
}

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

    //following commented line not needed anymore
    //Contato *contato = [contatos objectAtIndex:indexPath.row];

    cell.textLabel.text = [[[pl objectForKey:@"contatos"]
                               objectAtIndex:indexPath.row]
                                objectForKey:@"nome"];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //following commented line not needed anymore
    //Contato *contato = [contatos objectAtIndex:indexPath.row];

    //NOTE: fran is a dictionary now
    //change "fran" declaration in the ViewController.h to
    //NSDictionary *fran;
    fran = [[NSDictionary alloc] init];
    fran = [[pl objectForKey:@"contatos"]
               objectAtIndex:indexPath.row];

    NSLog(@"finalmente eu consegui essa porra!!!%@", fran);

    //...

    //don't deselectRow (the indexPathForSelectedRow will not work correctly later)
    //[self.tabelaContatos deselectRowAtIndexPath:indexPath animated:YES];
}

then on -prepareForSegue i'd pass the dictionary associated with the selected row:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"vai"]) {
        NSIndexPath *indexPath = [self.tabelaContatos indexPathForSelectedRow];
        perfilViewController *destViewController = segue.destinationViewController;

        //following commented line not needed anymore
        //Contato *contato = [contatos objectAtIndex:indexPath.row];

        //NOTE: fran is a dictionary now
        //change "fran" declaration in the ViewController.h to
        //NSDictionary *fran;  
        fran = [[NSDictionary alloc] init];
        fran = [[[pl objectForKey:@"contatos"]
                    objectAtIndex:indexPath.row]
                     objectForKey:@"fram"];

        //NOTE: destViewController.frans should be a dictionary
        //handle it appropriately
        destViewController.frans = fran;
    }
}

so basically, all dictionary use, no need for Contato *contato at all.

EDIT: As for your current method, you would be better off replicating the same structure.
As in:

[array of names] has {dictionary with user details} having a key that has {dictionary of frams}

OTHER TIPS

I'd recommend you not using a dictionary to store your Fram values, use an array instead. This way, you can get the Fram values like this:

for (NSDictionary *item in dados) {
    NSString *nome = [item valueForKey:@"nome"];
    NSString *telefone = [item valueForKey:@"telefone"];
    NSArray *fram = [item valueForKey:@"fram"];

    Contato *c = [[Contato alloc] initWithNome:nome andTelefone:telefone andFram:[fram objectAtIndex:index]];
    [contatos addObject:c];    
}

Where index is an integer variable you'll have to work out how to handle.

PS: be a little more polite when logging you app ;)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top