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.
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:
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:
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
– user3618255
Perfect, helped me a lot ! I needed to make an example of directory, with tableview and started from your example. Thank you very much
– user13807