views:

113

answers:

1

Hi all,

I wish to make a city/country selector using 2 NSPopupButtons. One popup button will contain the first part e.g. UK, and the second one will contain the second part e.g. London So the whole city/country combo will read: UK London however, I want the second part to be updated when the first part is selected, e.g. if London is selected, the possible choices in the second popupbutton will be London, Birmingham, Manchester etc., whilst if Italy was chosen, then the second popupbutton will display countries such as Venice, Milan etc.

Afterwards, I would like to store this data in one attribute in Core Data. so to join the two together, and store "UK London" in a attribute called "place".

Could anybody give me some help as to how to implement this please?

Thank you!

+2  A: 

How do you have your country / city data stored (are they also in Core Data)? That will determine some of the details here, but the basic idea is that you use Cocoa bindings to link each NSPopUpButton to the content of an NSArrayController.

Cocoa Bindings aren't terribly simple, but they really do work like magic once you get everything configured correctly. The trouble is that when you don't have things configured correctly, it's hard to determine what is going wrong.

Here's the general setup:

You configure the first NSArrayController to be the content of your Country Data. If you use Core Data, then you pass it the managed object context and have it prepare its own data for your Country entity. Otherwise, you'll have to bind its content to an existing array of objects that implement a Key-Value Coding compliant method of accessing their linked cities. Using core data for the data source here will make your life easier.

And then you bind the second NSArrayController to the get its content from the selection of the first, with the appropriate key path to your Cities. With Core Data, this will be the Content Set (since it's unordered).


Edit: Bah, comment fields are completely worthless. Here's a proper response to your first comment:

To model this relationship in Core Data, you'd to set up your model to look like this:

Xcode Model Editor Screenshot

It's important to note that I've given my entities custom classes (MBCountry and MBCity). By asking Xcode to generate the classes for you (select the entity, go to New File..., and choose Cocoa Class -> Managed Object Class), you can use real accessor methods (instead of just valueForKey:). (As an aside, I really value Rentzsch's Mogenerator that does this automatically for you on every save.)

Now that your model is set up, you can populate the data store like this:

NSArray *countryList = ...; /* Get your array of country names */
for (NSString *countryName in countryList) {
    MBCountry *aCountry = (MBCountry *)[NSEntityDescription insertNewObjectForEntityForName:@"MBCountry" inManagedObjectContext:context];
    [aCountry setName:countryName];
    NSArray *cityList = ... /* Get your array of city names for this country */
    for (NSString *cityName in cityList) {
        MBCity *aCity = (MBCity *)[NSEntityDescription insertNewObjectForEntityForName:@"MBCity" inManagedObjectContext:context];
        [aCity setName:cityName];
        [aCountry addCitiesObject:aCity];
    }
}

Core Data really is way overkill here. However, it sounds like you want to use Core Data in other sections of your program, so this makes for a great learning opportunity. It has a very steep learning curve (certainly one of the trickiest aspects of the Cocoa API), but it is doable. Just keep plugging away!

Matt B.
Thanks for your reply, if afraid I'm a bit confused as to what to do.If I use core data, do I have to make an entity for every single country? If not, how do I setup the country entity?
Michael
See my followup in the original answer.
Matt B.
Thanks for the awesome tutorial! I shall try that out!
Michael