-1

Firstly, sorry if the title is confusing, I'm not sure how else to word it. I'll explain my app briefly.

User is presented with a Login screen (very basic, no server-side stuff), in which they can log in to three different companies (Company A, Company B, and Company C) in that specific order. Once the user has successfully logged on to Company A, they are presented with a TableView. The LoginViewController (normal ViewController) downloads a ListOfClinics.xml file from Dropbox and parses it using NSXMLParser, and passes the object to the ClinicsViewController to displays a list of Clinic locations.

ListOFClinics.xml example:

<Clinic>
    <Location>
        <Clinic_Location>Manchester</Clinic_Location>
    </Location>
    <Location>
        <Clinic_Location>Liverpool</Clinic_Location>
    </Location>
    <Location>
        <Clinic_Location>Birmingham</Clinic_Location>
    </Location>
    <Location>
        <Clinic_Location>London</Clinic_Location>
    </Location>
    <Location>
        <Clinic_Location>Leeds</Clinic_Location>
    </Location>
</Clinic>

ClinicViewController is a TableViewController. While the table is being populated, the app downloads another file from Dropbox (Clients.xml) and parses it ready to be used. The idea is that a user can tap on a TableView cell containing a location, such as Manchester, and the newly parsed data from the Clients.xml should get passed to the next view (ClientsViewController) and show all clients registered to the Manchester clinic.

Clients.xml example:

<Client>
    <Clinic_Location>Manchester</Clinic_Location>
    <Client_Forename>Frank</Client_Forename>
    <Client_Surname>Wade</Client_Surname>
    <Client_Address_Line_1>Law Lane</Client_Address_Line_1>
    <Client_Address_Line_2>Money House</Client_Address_Line_2>
    <Client_Address_Line_3>Didsbury</Client_Address_Line_3>
    <Client_Address_Line_4>Manchester</Client_Address_Line_4>
    <Client_Address_Line_5></Client_Address_Line_5>
    <Client_Postcode>M20 2WS</Client_Postcode>
    <Client_Tel>01615559090</Client_Tel>
    <Appt_Time>15:30</Appt_Time>
    <Appointment_Attended>Booked</Appointment_Attended>
    <Passed_To_Medical>Complete Pass</Passed_To_Medical>
    <Passed_To_Sol>no</Passed_To_Sol>
</Client>
<Client>
    ...
</Client>

As you can see, both .xml files have the Clinic_Location element. I'm not too worried about error checking to make sure the data in these match up (the .xml files are exported via another system, so both should have the same locations). What I need to implement is that when someone taps on Manchester, the next TableView is presented with a list of Clients who are registered to the Manchester Clinic.

Update

I have created a new NSObject class, declaring all properties in ClientData.h and synthesising them in ClientData.m.

ClientData.h
@interface ClientData : NSObject

@property (strong) NSString *clinicLocation;
@property (strong) NSString *foreName;
...

ClientData.m
@implementation ClientData

@synthesize clinicLocation;
@synthesize foreName;
...

Below is a snippet of my parser component, using KVC to store the parsed data.

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

    if ([elementName isEqualToString:@"Client"]) {
        // save to data structure object with KVC
        ClientData *clientData = [[ClientData alloc]init];
        clientData.clinicLocation = clinicLocation
        clientData.foreName = foreName;
        ...

        // count number of clients
        clientCount++;
        [client setObject:clinicLocation forKey:@"Clinic_Location"];
        [client setObject:foreName forKey:@"Client_Forename"];
        ...
        [dataStart addObject:[client copy]];
    }
}

If I log the NSObject string with NSLog(@"Forename: %@", clientData.foreName);, etc, the output is correct.

KVC output

I am using a storyboard with segues to push the next view. Should I implement prepareForSegue to pass the NSObject (ClientData) or tableView didSelectRowAtIndexPath? Here is what I have tried:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
        if ([[segue identifier] isEqualToString:@"showClients"]) {

            // clientData is declared on the destinationViewController
            PCClientsViewController *pcClients = segue.destinationViewController;
            pcClients.clientData = [[ClientData alloc]init];
            pcClients.clientData.foreName = foreName;
        }
}

This works, although only one foreName value is getting passed through to the next TableView. Does my NSObject class only store one value each time I'm assigning something to it? In other words, If I parse 100 records with 100 foreName attributes, are all 100 values persisted or only the last one?

I still don't know what test to do here and only pass relevant data to the next view (ie. if user taps on Manchester, pass all Clients with a Clinic_Location of Manchester to the next view). Should I create a new NSObject class to store the ListOfClinics.xml data and test it against the CLinic_Location value in my ClientData NSObject?

rosshump
  • 370
  • 1
  • 4
  • 21

2 Answers2

1

Create a simple data structure object and pass that.

@interface ClientData
@property (strong) NSString *foreName;
@property (strong) NSString *surName;
// etc.
@end

@interface TargetViewController
@property (strong) ClientData *clientData;
@end
Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
  • Thanks for the reply. Please see my updated post: I have implemented your solution, but I am struggling with passing only relevant data to the next view (see last paragraph). – rosshump Jan 21 '15 at 09:32
  • You should be using `clientData.clinicLocation = clinicLocation` or `[clientData setClinicLocation:clinicLocation]` instead of `[clientData setValue:clinicLocation forKey:@"clinicLocation"]`. These methods are already created for you when you use `@property`. – Ian MacDonald Jan 21 '15 at 14:10
  • Ok thanks, that's handy to know! I have updated my question with you're code. This seems to work well, now I can pass through some data such as `foreName`, although only the last parsed `foreName` value gets passed. Do the values in my `NSObject` class get overwritten each time? I have 100+ client records, so for example if there 10 `Clinic_Location` tags with Manchester, when I tap on Manchester I should see those 10 clients and all details (`surName, address, postcode`, etc). Have I approached this the wrong way? I didn't want to complicate things with Core Data... – rosshump Jan 21 '15 at 14:39
  • Apologies for another comment, but couldn't I just pass the `NSMutableArray` created when parsing the data? If you look at my `parser didEndElement` method in my question, the array `datastart` holds all client data. I have done a quick test and I can pass this to the next TableView with `pcClients.clientArray = dataStart;` and display all client forenames with `cell.textLabel.text = [[_clientArray objectAtIndex:indexPath.row]objectForKey:@"Client_Forename"];`. Could I not do a test before this and only display each client relating to the `Clinic_Location` on the previous TableView cell? – rosshump Jan 21 '15 at 15:54
  • You can pass whatever you like. I personally suggest sticking with a data object that represents what you're doing rather than using dictionaries and arrays. It's cleaner, fewer characters to type, and allows your IDE to auto-complete properties for you. If you have more than one client to pass, construct an array of clients, but I still recommend the client object. – Ian MacDonald Jan 21 '15 at 16:05
  • Thanks for your advice, I do agree that a custom `ClientData` object is easier with the auto-complete properties etc, but I'm having difficulty learning how to implement it properly. I think I'll just pass the `Client` `array` and somehow compare its elements with the `ListOfClinics` `array`. Thanks for your help though, I really appreciate it. – rosshump Jan 22 '15 at 07:38
1

In the prepareForSegue, pcClients's property clientData is nil, if you assign its property forename any value it won't be saved as it has no memory allocated to save it. You can do this to solve your problem:

pcClients.clientData = [ClientData alloc] init];
pcClients.clientData.foreName = foreName;
dibi
  • 3,257
  • 4
  • 24
  • 31
Gunjit
  • 81
  • 3
  • Thanks for the reply. I have updated my question with your solution implemented, but the `NSLog` still displays `(null)` when passing the data to the next view? – rosshump Jan 21 '15 at 13:37
  • 1
    The `NSLog` still displays `(null)` because you are printing the value before you assign it. – Ian MacDonald Jan 21 '15 at 14:11