Create a tableView with 616 items

Asked

Viewed 470 times

3

I have to create a table with 616 items, each item has 5 details.

Example:

Item 1 - Aspirin
Risco: Medio
Lactacao: Alto
Gravide: Bass

item 2 - Dipirona
Risco: Medio
Lactacao: Alto
Gravide: Bass ...

Only the item name will appear in the table (Aspirin, Dipirona, ...) When clicked on the table item, opens a detailviewcontroller to show the remaining content.

What’s the best way to do that? If there were few items until I would do it in the same hand, creating object instance, but with 616, as I do?

1 answer

7


I will describe here a solution that adopts the following architecture:

  • Data is local to the device, initially stored in non-volatile memory and is in format Property list;

  • Data is loaded from non-volatile memory and stored in dictionaries in memory. All data is read to memory at once and do not set a class Medicamento specific;

  • Drug risk grades are stored as strings

The first step is to create a . plist file containing all the data to be displayed. In the main menu, choose File > New > File... and then, within the iOS category, Resource > Property List. In this example, I named it Medicamentos.plist. You can then fill in the data manually. For this answer, I defined the file as containing a dictionary with key "medicines", which, in turn, is a vector containing a list of medications. Each individual drug is a dictionary containing keys "name", "risk", "lactacao" and "pregnancy". The file could start directly as a vector, but having a dictionary makes it easier to include other data in the future without having to change code based on old data.

Dados no formato plist

If you -click the file in the project browser, you can choose the option Open As > Source Code: the Xcode will display you the same data, this time in XML format:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>medicamentos</key>
    <array>
        <dict>
            <key>nome</key>
            <string>Aspirina</string>
            <key>risco</key>
            <string>Médio</string>
            <key>lactacao</key>
            <string>Alto</string>
            <key>gravidez</key>
            <string>Baixo</string>
        </dict>
        <dict>
            <key>nome</key>
            <string>Dipirona</string>
            <key>risco</key>
            <string>Médio</string>
            <key>lactacao</key>
            <string>Alto</string>
            <key>gravidez</key>
            <string>Baixo</string>
        </dict>
    </array>
</dict>
</plist>

If this data comes from a database, you can write a script that formats it in the above way to avoid having to type it. Also, it might be easier to edit as XML than visually.

You will then have an external representation of the data that will be part of the app Bundle generated by Xcode and installed on devices.

In the view controller master, you need to load the data and store it. In this example, I am storing it in an instance variable called _medicamentos:

@interface BAVMasterViewController ()
@property (nonatomic, copy) NSArray *medicamentos;
@end

In the method -viewDidLoad, write the following:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSURL *plistURL = [[NSBundle mainBundle] URLForResource:@"Medicamentos" withExtension:@"plist"];
    NSDictionary *plist = [NSDictionary dictionaryWithContentsOfURL:plistURL];
    self.medicamentos = plist[@"medicamentos"];
}

The first step is to get the URL that describes where the Medicamentos.plist file is stored inside the app Bundle. Done this, the method +[NSDictionary dictionaryWithContentsOfURL:] reads the data in plist format and creates a dictionary (remember that we define the .plist file as a dictionary) based on the file. The dictionary contains a single key called "medicines" whose value is a vector containing a list of medications. We store this vector in the property medicamentos.

Once this is done, just use the vector as the data from view controller master. Each element of this vector is a dictionary containing "name", "risk", "lactacao" and "pregnancy". In the master, we display the name of the medicine:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    NSDictionary *medicamento = self.medicamentos[indexPath.row];
    cell.textLabel.text = medicamento[@"nome"];
    return cell;
}

Resulting in:

Exemplo do view controller mestre

When the user touches a drug, we go to the view controller detail, passing the medication chosen by the user:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSDictionary *medicamento = self.medicamentos[indexPath.row];
        [[segue destinationViewController] setMedicamento:medicamento];
    }
}

Note that the view controller detail gets -setMedicamento: to find out which medicine to take. In addition, it contains Labels for each data displayed:

@interface BAVDetailViewController : UIViewController
@property (strong, nonatomic) NSDictionary *medicamento;
@property (weak, nonatomic) IBOutlet UILabel *riscoGeralLabel;
@property (weak, nonatomic) IBOutlet UILabel *riscoLactacaoLabel;
@property (weak, nonatomic) IBOutlet UILabel *riscoGravidezLabel;
@end

Upon receiving a medicine, it is stored and the view is configured:

- (void)setMedicamento:(NSDictionary *)medicamento
{
    if (medicamento != _medicamento) {
        _medicamento = medicamento;
        [self configureView];
    }
}

And, in the configuration of view, the details of the medicinal product are sent to Labels and the title of the detail is named after the medicine:

- (void)configureView
{
    // Update the user interface for the detail item.

    if (self.medicamento) {
        self.title = self.medicamento[@"nome"];
        self.riscoGeralLabel.text = self.medicamento[@"risco"];
        self.riscoLactacaoLabel.text = self.medicamento[@"lactacao"];
        self.riscoGravidezLabel.text = self.medicamento[@"gravidez"];
    }
}

Resulting in:

Exemplo do view controller detalhe

This is a simple solution. Some alternatives to the solution architecture:

  • Get data from web servers, perhaps with local caching in the application;

  • Use another serialization format. JSON is popular on web services and nothing prevents it from being used locally. If the data is many and having it all in memory (as with plist and JSON) is not feasible, you can use Core Data or Sqlite. The way you presented - 616 medications -, you don’t have to worry about memory;

  • Instead of using literal strings for dictionary keys, use constants. This prevents typos and makes it easy to change keys if and when needed;

  • Instead of using dictionaries to store data within the process, convert it from dictionaries to instances of a model class, and.g. Medicamento, which contains properties for each data. In this way, it becomes clearer which data is available and which types are available. The Mantle is a Github framework that can help you maintain these types of model classes;

  • Instead of storing risk gradations as strings, you can store them as numbers (e.g. 1 for Low, 2 for Medium, and 3 for High) and convert them to strings only when presenting the data. This will reduce the memory used by the process as numbers are represented more compactly than strings.

  • Hello, I wouldn’t call this the answer of a great tutorial, now let me ask you, and if I need to add a search with Nspredicate to filter with the names of the medicines how it would work that so I don’t miss the reference in detailviewcontroler, Thank you very much

  • Perfect, helped me a lot ! I needed to make an example of directory, with tableview and started from your example. Thank you very much

Browser other questions tagged

You are not signed in. Login or sign up in order to post.