help populating a uitableview

Discussion in 'iOS Programming' started by LARRYSE, Aug 22, 2012.

  1. LARRYSE, Aug 22, 2012
    Last edited by a moderator: Aug 22, 2012

    macrumors newbie

    Joined:
    Aug 22, 2012
    #1
    Help,

    I have been try to populate a tableview with a list of object properties. I have an object class, object controller class and my ui. I could just use a simple list and populate my table but in other parts of my program I will need objects with multiple properties to fill in other tableviews.

    Here is my code, I figure its a line or 2 that needs to be changed.

    ============ Object class ===============
    Code:
    #import <Foundation/Foundation.h>
     
    @interface Category : NSObject
    {
        NSString *name;
    }
     
    @property (copy, nonatomic) NSString *name;
     
    -(void) print;
     
    @end
     
     
    #import "Category.h"
     
    @implementation Category
     
    @synthesize name;
    -(void) setName: (NSString *) theCategory
    {
     
        name = [[NSString alloc] initWithString: theCategory];
    }
     
    -(void) print
    {
        NSLog(@"Category name: %-31s",[name UTF8String]);
    }
     
    @end
    

    ================ Object controller class ==================
    Code:
    #import <Foundation/Foundation.h>
    #import "Category.h"
     
    @interface Categories : NSObject
    {
        NSString        *categoryName;
        NSMutableArray  *categoryList;
        NSMutableArray  *testList;
    }
     
    -(id) initWithName: (NSString *) name;
    -(void) addCategory: (Category *) theCategory;
    -(int) enteries;
    -(void) list;
    -(NSMutableArray *) getList;
    -(void) testList;
    //-(void) dealloc;
     
    @end
     
     
     
    #import "Categories.h"
     
    @implementation Categories;
     
    - (id) initWithName: (NSString *) name
    {
        self = [super init];
        if (self)
        {
            categoryName = [[NSString alloc ] initWithName: name ];
            categoryList = [[NSMutableArray alloc] init ];
        }
     
        return self;
    }
     
    -(void) addCategory:(Category *)theCategory
    {
        [categoryList addObject: theCategory];
    }
     
    -(int) enteries
    {
        return [categoryList count];
    }
     
    -(void) list
    {
        NSLog(@"======= Contents of: %@ =======", categoryName);
     
        for (Category *theCategory in categoryList)
            NSLog (@"%-20s", [theCategory.name UTF8String]);
     
        NSLog (@"=======================================");
    }
     
    -(NSMutableArray *) getList
    {
        if([categoryList count] == 0)
        {
            [self testList ];
            for (int i =0; i < [testList count]; i++)
            {
                Category *cat = [[Category alloc] init];
                [cat setName: [testList objectAtIndex: i]];
                [categoryList addObject: cat];
            }
     
        }
        return categoryList;
     
    }
    -(void) testList
    {
        testList = [[NSMutableArray alloc] init];
        [testList addObject: @"item1"];
        [testList addObject: @"item2"];
        [testList addObject: @"item3"];
        [testList addObject: @"item4"];
        [testList addObject: @"item5"];
     
    }
    @end
    

    ========================== UI screen with table view ====================
    Code:
    #import <UIKit/UIKit.h>
     
     
    @interface FirstViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
    {
     
        NSMutableArray  *categoryList;
    }
     
    @property (nonatomic, retain) NSMutableArray * catList;
     
     
    @end
     
     
     
     
    #pragma - Tableview Methods
     
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return catList.count;
    }
     
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        //Step 1: Check to see if cell row can be reused
        UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
     
        //Step 2: If there are no cells to reuse create a new one
        if (cell == nil)
        {
            cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        }
     
     
        //Add a detail view accessory
        cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
     
        //Step 3: Set text
     
    //    cell.textLabel.text = ([categoryList valueForKey:@"name"]);
    [self getList];
     
    cell.textLabel.text = [categoryList valueForKey:@"name"];
    // cell.textLabel.text = [categoryList objectAtIndex:indexPath.row];
    cell.textLabel.font = [UIFont systemFontOfSize:17];
        cell.textLabel.numberOfLines = 0;
        cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
     
        //Step 4: return index row
        return cell;
    }
     
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        CGSize size = [[catList objectAtIndex:indexPath.row]
                       sizeWithFont:[UIFont systemFontOfSize:17]
                       constrainedToSize:CGSizeMake(200,CGFLOAT_MAX)];
     
        return size.height + 10;
    }
     
    -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    {
     
    cell.backgroundColor = (indexPath.row%2)?[UIColor lightGrayColor]:[UIColor clearColor];
    }
    
    Thanks an help will be appreciated.
     
  2. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #2
    hmm, I don't see anywhere where you actually create your Category object.
    For myself, for just creating a category with a name i'd make a method like this
    Code:
    - (id) initWithName:(NSString*)name; 
    And implementation ->
    Code:
     - (id) initWithName:(NSString*)name {
    self.name = name;
    }
    Then you don't need to create setters or anything (you don't needed to do that anyways, since you have a synthesized, which will create getters/setters for you.

    To actually create your object, put these in an array
    Code:
    Category *cat1 = [[Category alloc] initWithName:@"I LIEK TURTLES"];
    
    Now you can use it's name in the tableview cell, you're code was on it's way to do great.
    But you have to do this ->
    Code:
    Category *category = [arrayWithCategoryobjects objectAtIndex:indexpath.row];
    cell.textLabel.text = category.name //This will come from the synthesized getter
    
    Hope that helped you, if you have more questions, please do ask.
     
  3. macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #3
    What does this line do?
    Code:
    cell.textLabel.numberOfLines = 0;
     
  4. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #4
    Should set it so that it can use unlimited lines (0=unlimited)
     
  5. thread starter macrumors newbie

    Joined:
    Aug 22, 2012
    #5
    ok, I added this code to my category interface
    Code:
    - (id) initWithName:(NSString*)name;
    
    and this code to my category implementation
    Code:
     - (id) initWithName:(NSString*)name {
    self.name = name;
    }
    
    and I put this line in my category implementation where i create my array with category objects
    Code:
    Category *cat1 = [[Category alloc] initWithName:@"I LIEK TURTLES"];
    
    so when I add this line to my interface file to populate the tableview it does not recognize arrayWithCategoryobjects
    Code:
    Category *category = [arrayWithCategoryobjects objectAtIndex:indexpath.row];
    
    i know i'm missing something but don't know what.
    if you want i will repost my code pieces, I have seen arrayWith... before, but don't remember where

    thxs for your help so far
     
  6. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #6
    You didn't fully understand.

    arrayWithCategoryobjects -> I meant with this, you should create an array containg your custom objects

    Let's say like this.
    Code:
    NSMutableArray *categories = [[NSMutableArray alloc] init];
    for (int i = 0; i < 10 ; i++) {
     Category *cat = [[Category alloc] initWithName:[NSString stringWithFormat:@"Test cat: %i", i]];
     [categories addObject:cat];
    }
    

    Now you should be able to do this ->
    Code:
    Category *category = [categories objectAtIndex:indexpath.row];
    
    Where you need it, so make sure categories is avaialble in your class scope and not a method scope :)
    Hope I made that clear, and I hope you do understand what you are doing and not just copy pasting.
     
  7. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #7
    Seems likes this init is missing code from the usual approach. For example, where is the call to [super init]? Also, where is the return?
     
  8. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #8
    Yeah, thought he would fill it in himself, excuse me, here's the better version ->
    Code:
     - (id) initWithName:(NSString*)name {
       self = [super init];
       if (self) {
          self.name = name;
       }
       return self;
    }
    
     
  9. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #9
    Actually, Apple recommends that you don't use accessor methods to access properties in the init. So, a better version, assuming the instance variable backing the property is named _name, would be:
    Code:
    - (id)initWithName:(NSString *)name
    {
        self = [super init];
        if (self) {
            _name = name;
        }
        return self;
    }
    
     
  10. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #10
    I learn each day, thought that didn't really matter.. I only knew you shouldn't set outles in the init, since the NIB couldn't be loaded yet.
    Thanks Dejo.

    Noxx.
     
  11. thread starter macrumors newbie

    Joined:
    Aug 22, 2012
    #11
    I got it all working. I followed and understand what you posted. I brain farted the the list part last post. This will be a big help going forward in showing me my mistakes, like forgetting my constructor in my object class as well as using the super init (much like java).

    Although it is a very basic program it is my first objective c/iphone app.

    Thanks for all your assistance and I will change self.name to _name.
    Larry
     
  12. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #12
    You can use self.name for accessing the property (to know what's in it).
    So if you have other methods that will acces it, there's no problem using self.name there.
     
  13. dejo, Aug 29, 2012
    Last edited: Aug 29, 2012

    Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #13
    Yeah, you should use self.name everywhere within the implementation except in init and dealloc methods.
     
  14. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #14
    I'm curious why you would ignore it in the dealloc. Since apple's autogenerated code mostly does --> self.blah = nil;
    or am I mistaking?
     
  15. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #15
    Because that is what the Advanced Memory Management Programming Guide says:
    Seems Apple has Xcode violating their own memory management principles.

    Plus, I believe some of these concerns are going away even more in future Xcodes / iOS SDKs based on some of the things I see with Xcode 4.5 / iOS 6 (such as: auto-synthesis, viewDidUnload deprecated, etc.)
     
  16. macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #16
    Well and if you override the setter or getter of that property. Otherwise you win a free trip to Apple HQ. ;-)
     
  17. jnoxx, Aug 30, 2012
    Last edited: Aug 30, 2012

    macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #17
    Damnit Apple.. :p
    I also hate the code convencience (where to put the curley brackets behind a method), spaces between (void)methodName or (void) methodName
    All these things, if you download different Apple samples, they are different.
    But thanks for that quote, i should've read it better.
    And I was mistakin, i was talking about viewDidUnload, is setting the self.property's to nil, and not the dealloc. Since i've been working with ARC, i was confused. but that's definitly a good read to pickup on older projects.
    (I allways did [_blah release] in pre-ARC).

    PS:mad:Dejo, I have looked through the guide, they say that's only needed if you're using KVO patterns in your code, since it could send the wrong value to the patterns on the wrong time, for normal programming, you should/could use the setters/getters created from the synthesize :)
     
  18. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #18
    Yeah, seems I was mistaken as well, as well, since I didn't pick-up on that issue. Anyways, the auto-generated self.property = nil goes into the viewDidUnload, which in the future, will be gone so no need to worry about it. Admittedly though, Apple does sometimes have problems keeping their documentation up to date with their tools.

    And with ARC, there's no longer a need to worry about this, so even less of a need to code anything in the dealloc. I only use it nowadays for very special occassions.
     

Share This Page