Seque Plist?

Discussion in 'iOS Programming' started by trey5498, Feb 13, 2014.

  1. trey5498 macrumors regular

    Joined:
    Jun 16, 2008
    #1
    I have successfully populated a UIPickerView with the contents of a plist.

    Here is the example of the list:
    Code:
    <dict>
    	<key>States</key>
    	<array>
    		<dict>
    			<key>StateName</key>
    			<string>Alabama</string>
    			<key>Est</key>
    			<string>1819</string>
    			<key>Cap</key>
    			<string>Montgomery</string>
    			<key>Pop</key>
    			<string>4822023</string>
    			<key>Large</key>
    			<string>Birmingham</string>
    			<key>Flag</key>
    			<string>Alabama.jpg</string>
    		</dict>
    
    I have done this with:

    Code:
    NSString *StatePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];
    NSDictionary *StateDictionary = [[NSDictionary alloc] initWithContentsOfFile:StatePath];
    
    _StatesNames = StateDictionary[@"States"];
    _States = [_StatesNames valueForKeyPath:@"StateName"];
    
    Now I am having issue in segueing this plist to to a Details ViewController. I am not sure how to capture each state in the above plist example for the selected state. Does anyone have an idea how to tackle that?
     
  2. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #2
    I would probably create a State class and then "convert" the dictionary for that state into a State object.
     
  3. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #3
    similar to what i did above:

    Code:
    NSString *StatePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];
    NSDictionary *StateDictionary = [[NSDictionary alloc] initWithContentsOfFile:StatePath];
    
     
  4. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #4
    No, what I mean is something more like:
    Code:
    NSString *StatePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];
    NSDictionary *StatesDictionary = [[NSDictionary alloc] initWithContentsOfFile:StatePath];
    NSArray *statesArray = [StatesDictionary objectForKey:@"States"];
    NSDictionary *aStateDictionary = [statesArray objectAtIndex:0];
    State *aState = [State stateFromDictionary:aStateDictionary];
    where State is a custom-built class.

    P.S. variable names such as StatePath and StateDictionary don't follow coding conventions, where variables start with lower-case. They look like class names, which normally start with upper-case. I'd suggest you name them statePath and stateDictionary instead.

    Once you have the info in a State object, there are a number of ways to share that object with the Detail View Controller.
     
  5. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #5
    Plist information pulling?

    I did not want to bump an old thread since it has been a bit since my last post.

    I have successfully populated a UIPickerView with the contents of a plist and want to pull the information associated with it.

    Here is the example of the list:

    Code:
    <dict>
    	<key>States</key>
    	<array>
    		<dict>
    			<key>StateName</key>
    			<string>Alabama</string>
    			<key>Est</key>
    			<string>1819</string>
    			<key>Cap</key>
    			<string>Montgomery</string>
    			<key>Pop</key>
    			<string>4822023</string>
    			<key>Large</key>
    			<string>Birmingham</string>
    			<key>Flag</key>
    			<string>Alabama.jpg</string>
    		</dict>
                     <dict>
    			<key>StateName</key>
    			<string>Alabama2</string>
    			<key>Est</key>
    			<string>1819</string>
    			<key>Cap</key>
    			<string>Montgomery</string>
    			<key>Pop</key>
    			<string>4822023</string>
    			<key>Large</key>
    			<string>Birmingham</string>
    			<key>Flag</key>
    			<string>Alabama.jpg</string>
    		</dict>
    ..................
    
    The <dict> inside the array shows up at item0, item 1 ...etc.... when I open the plist in xcode 5.

    I can get the list of the state names and then I am able to use the picker to select a value of a single state and use it for other purposes.

    What I am unable to do is to grab the rest of the keys. When I try:

    Code:
    NSString *StateDict = [NSString stringWithFormat:@"%@", [[NSUserDefaults standardUserDefaults] dictionaryForKey:SelectedState]];
    I get null. I don't even get the item0, item1 and so forth. How would I grab the rest of the <dict> and then use it as an array. I tried looking up custom classes, however, I only come up with custom classes for TableViews, PickerViews, Labels, etc.... Ideally this would be perfect use of an array or a collection.

    Can only one get me stated?
     
  6. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #6
    Mod voice: It wouldn't be considered a bump since you are adding new information. As such, I've merged it with the original thread.

    What I meant by "custom class" is that you should create your own class to hold the state information. Since you didn't understand what I meant, can I ask what your comfort-level is with Objective-C / OOP programming? What resources have you used to learn the fundamentals? Please be as specific as possible.
     
  7. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #7
    My comfort level is this. I am a very confident coder in python, powershell and perl. I have also had some real world experience in C++ and Objective-C (although, nothing with Plists and mostly simple). I am currently taking a Mobile Programming class as I want to expand that knowledge and as I am a programmer by trade.... I naturally try to push the envelope to learn.

    I did use collections before, which can be a type of class, but have never used them or created them in objective-c.

    Thanks for the migration. I did not know if that would be considered a bump.. I have used another forum that did... but then again that was a long while ago.
     
  8. trey5498, Feb 14, 2014
    Last edited: Feb 14, 2014

    trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #8
    I appreciate your patience with me, as I am not asking for you to do the work for me. I only ask for confirmation (or a slap in the back of the head with a point in the right direction). The only thing I can think that will work maybe to create an NSObject and then call it. I do believe that is what you meant.

    Code:
    stateDataClass.h
    
    @interface stateDataClass : NSObject {}
    	@property (nonatomic, copy) NSString *stateName;
    	@property (nonatomic, copy) NSString *estDate;
    	@property (nonatomic, copy) NSString *capital;
    	@property (nonatomic, copy) NSString *largeCity;
    	@property (nonatomic, copy) int *population;
    	@property (nonatomic, copy) NSString *flagImage;
    @end
    
    And maybe create the rest of the searchable array this way?

    Code:
    NSString *StatePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];
    NSDictionary *StateDictionary = [[NSDictionary alloc] initWithContentsOfFile:StatePath];
    NSMutableArray *stateDetails= [[NSDictionary alloc] init];
    
    //Creates the list of States for the UIPickerView
    _StatesNames = StateDictionary[@"States"];
    _States = [_StatesNames valueForKeyPath:@"StateName"];
    
    //Creates the array with the State details
    for (NSDictionary *stateDict in _StatesNames) {
        stateDataClass *detail = [[stateDataClass alloc] init];
        detail.stateName = [stateDict objectForKey:@"StateName"];
        detail.estDate = [stateDict objectForKey:@"Est"];
        detail.capital = [stateDict objectForKey:@"Cap"];
        detail.largeCity = [stateDict objectForKey:@"Large"];
        detail.population = [stateDict objectForKey:@"Pop"];
        detail.flagImage = [stateDict objectForKey:@"Flag"];
        [stateDetails addObject:detail];
    }
    or do you happen to know a better way?
     
  9. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #9
    Looks pretty good to me. A couple of things: 1) you're not creating an NSObject; you're defining a new class that happens to be a subclass of NSObject, 2) see the line I highlighted; it's probably not what you want.
     
  10. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #10
    so after a long weekend of sitting at mechanic shops and finally car dealerships.. I have finally gotten back to this. Here is the update I got...

    Code:
    NSString *StatePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];
        NSMutableDictionary *StateDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:StatePath];
        _stateDetails = [[NSMutableArray alloc] initWithCapacity:50];
        
        
        //Creates the list of States for the UIPickerView
        _StatesNames = StateDictionary[@"States"];
        _States = [_StatesNames valueForKeyPath:@"StateName"];
        
        //Creates the array with the State details
        for (NSDictionary *stateDict in _StatesNames) {
            stateDataClass *detail = [[stateDataClass alloc] init];
            detail.stateName = [stateDict objectForKey:@"StateName"];
            detail.estDate = [stateDict objectForKey:@"Est"];
            detail.capital = [stateDict objectForKey:@"Cap"];
            detail.largeCity = [stateDict objectForKey:@"Large"];
            detail.population = [stateDict objectForKey:@"Pop"];
            detail.flagImage = [stateDict objectForKey:@"Flag"];
            [_stateDetails addObject:detail];
        }
    
    Now I am trying to pull that info out of the array by way of selecting the object through the pickerview with:

    Code:
     NSString *SelectedState = [_States objectAtIndex:[_StatePickerView selectedRowInComponent:0]];
    
    this returns the name of the state (IE: Alaska) and I can search the array created and find alaska, but I know there has to be a prefered method like

    Code:
    Example:
    statPopLabel.text =  [_stateDetails valueForKey:SelectedState.population]
    
    Am I close to the right track with this thought or where should I be leaning towards?
     
  11. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #11
    First, you're still not following common Objective-C coding conventions of class names starting with upper-case and variables starting with lower-case. For example, the above, highlighted line is confusing because, at first glance, stateDataClass and detail appear to be the same kind of thing. They're not. Your class name should be StateData. (No need for the "Class" suffix; avoid being self-referential). You should also go back and adjust StatePath, StateDictionary, _StatesNames and _States. I would also revisit your variable names since they can be confusing. For example, _States is an array that actually contains state names, but _StateNames is already taken.

    Second, you now have a _stateDetails array containing stateDataClass StateData objects. You should access its members the same way you are accessing the members of your _States array. That is, why not use objectAtIndex:?
     
  12. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #12
    I know my naming convention isn't the best... In fact, to be honest in most of the code I have ever written (as in above mostly scripting) all is lowercase. I also tend to document inside the code whenever possible (usually after I know it works so I can go back and understand it when I look at it later down the road). I did not know the convention for Objective-C was what you said until this thread. The class I am taking isn't that clear on the subject. I will change it after I solve my issues.

    You are also 100% right on the array names should be changed, but for the sake of this thread I kept it the same so others could easily follow.

    With the _stateDetails holding 50 of these:
    Code:
    [0]	stateDataClass *
    NSObject	
    _stateName =	__NSCFString *	@"Alabama"
    _estDate =	__NSCFString *	@"1819"
    _capital =  	__NSCFString *	@"Montgomery"
    _largeCity =	__NSCFString *	@"Birmingham"
    _population =	__NSCFString *	@"4822023"
    _flagImage =	__NSCFString *	@"Alabama.jpg"
    

    and the code (example to get values):
    Code:
    NSString *stateTexas = @"Texas";
    NSString  *objectOfTexas = [_stateDetails objectAtIndex:42];
    NSUInteger indexOfTexas = [_stateDetails indexOfObject:stateTexas];
        
    NSLog(@"Object at index 42 is: %@", objectOfTexas);  //returns the entire NSObject that holds all the information
    NSLog(@"The Index of Texas is %tu", indexOfTexas);  //returns 2147483647
    
    in theory an easy way to get index number of each state would be to (example):
    Code:
    
    //_stateNames is formerly _States from above and selectedState would be the value selected by the UIPickerView
    NSUInteger indexOfState = [_stateNames indexOfObject:selectedState];  //returns 42
    
    Then I could use that index along with the [_stateDetails objectAtIndex:indexOfState] to get the information, but how would I grab the details out of the array without creating a new one to populate the labels?

    IE: Populate the stateCapitallbl.text

    As you can see, I really am trying to challenge myself with things that will be relevant in real life and not what is in the class room just to get a passing grade. I want to learn it to be able to use it.
     
  13. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #13
    _stateDetails in an array containing StateData objects, correct? Then objectAtIndex: isn't going to return an NSString object but a StateData object. Also, you are asking for the indexOfObject: for an object that doesn't exist in the array here. _stateDetails is an array of StateData objects, not NSString objects.

    Anyways, if both your UIPickerView and _stateDetails are built using the same plist, than the index from the picker should provide the same state in the array, right?

    Have you studied how to access the properties of an object yet?
     
  14. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #14
    Since it has been about 10 years since the last time I ever needed to use a custom object class (or collections as they are called by other languages). I am a tad bit rusty at some areas.

    They are both built from the plist. I have created (before this thread) a simple go button that would show an alert with the state name (will replace it with a segue once I figure out the information grab) and use the following to obtain the name

    Code:
    //titleForRow function.  fills the UIPickerView and _stateNames is formally _States
    return [_stateNames objectAtIndex:row];
    
    
    //located in the button pressed function
    NSString *selectedState = [_States objectAtIndex:[_statePickerView selectedRowInComponent:0]];
    


    No and in this class, we will not be. Since personally I believe it is bad form to have information hard coded in arrays. I took it upon myself to learn plists.

    Any function I need to look for to grab each information out of the NSObject?
     
  15. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #15
    Um, it's not an NSObject. It's a custom object, who class happens to be a subclass of NSObject. I think you're better off if you try to think of NSObject as little as possible.

    Anyways, accessing the properties of an object is a basic concept that is covered pretty early on in most introductions to Objective-C. If your goal is to not "just to get a passing grade" but to "learn it to be able to use it", I would suggest at this point that you step away from the real coding and spend some time learning the fundamentals of Objective-C programming. This will help you in the long run because you'll want that foundation from which to build upon.
     
  16. trey5498 thread starter macrumors regular

    Joined:
    Jun 16, 2008
    #16
    For future readers of this post:

    Code:
        NSString *selectedState = [_stateNames objectAtIndex:[_statePickerView selectedRowInComponent:0]];
        NSUInteger indexOfState = [_stateNames indexOfObject:selectedState];
        NSString *objectOfState = [_stateDetails objectAtIndex:indexOfState];
        stateCapitallbl.text = [objectOfState valueForKey:@"_capital"];
    
    That code will solve my issue. I am sure there is an easier way and I am looking into this subject more, since the class book just grazes the subject if at all.

    All trial error and internet research. Thank you again for your patience.
     
  17. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #17
    I don't believe your [_stateDetails objectAtIndex:indexOfState] returns an NSString. And then calling valueForKey: on an NSString doesn't make sense.
     

Share This Page