iOS help populating a uitableview

LARRYSE

macrumors newbie
Original poster
Aug 22, 2012
12
0
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.
 
Last edited by a moderator:

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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.
 

LARRYSE

macrumors newbie
Original poster
Aug 22, 2012
12
0
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
 

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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.
 

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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?
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;
}
 

dejo

Moderator
Staff member
Sep 2, 2004
15,981
447
The Centennial State
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;
}
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;
}
 

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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;
}
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.
 

LARRYSE

macrumors newbie
Original poster
Aug 22, 2012
12
0
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
 

dejo

Moderator
Staff member
Sep 2, 2004
15,981
447
The Centennial State
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?
Because that is what the Advanced Memory Management Programming Guide says:
Don’t Use Accessor Methods in Initializer Methods and dealloc
The only places you shouldn’t use accessor methods to set an instance variable are in initializer methods and dealloc.
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.)
 

MattInOz

macrumors 68030
Jan 19, 2006
2,761
0
Sydney
Yeah, you should use self.name everywhere within the implementation except in init and dealloc methods.
Well and if you override the setter or getter of that property. Otherwise you win a free trip to Apple HQ. ;-)
 

jnoxx

macrumors 65816
Dec 29, 2010
1,343
0
Aartselaar // Antwerp // Belgium
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.)
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 :)
 
Last edited:

dejo

Moderator
Staff member
Sep 2, 2004
15,981
447
The Centennial State
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.
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.

(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 :)
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.