PDA

View Full Version : help populating a uitableview




LARRYSE
Aug 22, 2012, 01:46 PM
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 ===============

#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 ==================

#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 ====================

#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.



jnoxx
Aug 23, 2012, 01:40 AM
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
- (id) initWithName:(NSString*)name;
And implementation ->
- (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

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 ->
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.

MattInOz
Aug 23, 2012, 04:34 AM
What does this line do?
cell.textLabel.numberOfLines = 0;

jnoxx
Aug 23, 2012, 07:57 AM
What does this line do?
cell.textLabel.numberOfLines = 0;

Should set it so that it can use unlimited lines (0=unlimited)

LARRYSE
Aug 26, 2012, 03:24 PM
ok, I added this code to my category interface

- (id) initWithName:(NSString*)name;


and this code to my category implementation

- (id) initWithName:(NSString*)name {
self.name = name;
}


and I put this line in my category implementation where i create my array with category objects

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

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
Aug 27, 2012, 12:58 AM
You didn't fully understand.

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

Let's say like this.

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 ->

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.

dejo
Aug 27, 2012, 09:51 AM
- (id) initWithName:(NSString*)name {
self.name = name;
}


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?

jnoxx
Aug 27, 2012, 11:02 AM
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 ->

- (id) initWithName:(NSString*)name {
self = [super init];
if (self) {
self.name = name;
}
return self;
}

dejo
Aug 27, 2012, 12:44 PM
Yeah, thought he would fill it in himself, excuse me, here's the better version ->

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

- (id)initWithName:(NSString *)name
{
self = [super init];
if (self) {
_name = name;
}
return self;
}

jnoxx
Aug 27, 2012, 01:16 PM
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:

- (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
Aug 28, 2012, 11:29 AM
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

jnoxx
Aug 29, 2012, 01:35 AM
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.

dejo
Aug 29, 2012, 08:38 AM
Yeah, you should use self.name everywhere within the implementation except in init and dealloc methods.

jnoxx
Aug 29, 2012, 02:16 PM
Yeah, you should use self.name everywhere within the implementation except in init and dealloc methods.

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?

dejo
Aug 29, 2012, 07:08 PM
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 (https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011-SW1) 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
Aug 29, 2012, 09:09 PM
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
Aug 30, 2012, 02:55 AM
Because that is what the Advanced Memory Management Programming Guide (https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011-SW1) 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:@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 :)

dejo
Aug 30, 2012, 08:37 AM
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:@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.