1

I'm pretty new to objective-C (and C in general) and iPhone development and am coming from the java island, so there are some fundamentals that are quite tough to learn for me.

I'm diving right into iOS5 and want to use storyboards.

For now I am trying to setup a list in a UITableViewController that will be filled with values returned by a web service in the future. For now, I just want to generate some mock objects and show their names in the list to be able to proceed.

Coming from java, my first approach would be to create a new Class that provides a global accessible method to generate some objects for my list:

#import <Foundation/Foundation.h>

@interface MockObjectGenerator : NSObject

+(NSMutableArray *) createAndGetMockProjects;

@end

Implementation is...

#import "MockObjectGenerator.h"

// Custom object with some fields    
#import "Project.h"

@implementation MockObjectGenerator

+ (NSMutableArray *) createAndGetMockObjects {

    NSMutableArray *mockProjects = [NSMutableArray alloc];

    Project *project1 = [Project alloc];
    Project *project2 = [Project alloc];
    Project *project3 = [Project alloc];

    project1.name = @"Project 1";
    project2.name = @"Project 2";
    project3.name = @"Project 3";

    [mockProjects addObject:project1];
    [mockProjects addObject:project2];
    [mockProjects addObject:project3];

    // missed to copy this line on initial question commit
    return mockObjects;

}

And here is my ProjectTable.h that is supposed to control my ListView

#import <UIKit/UIKit.h>

@interface ProjectsTable : UITableViewController

@property (strong, nonatomic) NSMutableArray *projectsList;

@end

And finally ProjectTable.m

#import "ProjectsTable.h"
#import "Project.h"
#import "MockObjectGenerator.h"

@interface ProjectsTable {

@synthesize projectsList = _projectsList;

-(id)initWithStyle:(UITableViewStyle:style {

    self = [super initWithStyle:style];

    if (self) {

        _projectsList = [[MockObjectGenerator createAndGetMockObjects] copy];

    }

    return self;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // only one section for all
    return 1;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    NSLog(@"%d entries in list", _projectsList.count);
    return _projectsList.count;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // the identifier of the lists prototype cell is set to this string value
    static NSString *CellIdentifier = @"projectCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    Project *project = [_projectsList objectAtIndex:indexPath.row];

    cell.textLabel.text = project.name

    return cell;
}

So while I think everything is correctly set, I expect the tableView to show my three mock objects in its rows. But it stays empty and the NSLog method prints "0 entries in list" into the console. So what am I doing wrong?

Any help is appreciated.

Best regards Felix

Update 1: missed to copy the two return statements into this box ("return mockObjects" and "return cell") which were already in my code, now inserted.

Felix
  • 101
  • 6

3 Answers3

1

You're missing

return mockProjects;

in your method

+ (NSMutableArray *) createAndGetMockObjects {

EDIT

Also, like everyone else is pointing out, you need to make sure to call init on all of the objects you are allocating. Simply allocating it does not initialize the object, and you can't really use it until you do so

Dan F
  • 17,654
  • 5
  • 72
  • 110
1

You have at least two problems in your code:

In

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

You are supposed to return a valid UITableViewCell (just return cell;)

You should also init the objects you allocate:

NSMutableArray *mockProjects = [NSMutableArray alloc];

Project *project1 = [Project alloc];
Project *project2 = [Project alloc];
Project *project3 = [Project alloc];

To do so write mockProjects = [[NSMutableArray alloc]init]; and same for the Project objects.

In the method you also need to return the object you create: return mockProjects;

I would strongly recommend that you check up on the Automatic reference Counting system, or try to learn the good ol' fashioned memory management model of iOS. It is very different from the Java way of doing things.

EsbenB
  • 3,356
  • 25
  • 44
  • Also needs to init the three Project objects. – JeremyP Jun 28 '12 at 15:13
  • ah I see, so `alloc` is just a hint for the system to prepare some memory for the object, and `init` actually fills the object with life? So why doesn't the compiler complain about the objects not being initialized? Is it because C is more machine-oriented? – Felix Jun 29 '12 at 07:38
  • Yes. Exactly alloc, allocates the memory needed for the object. init is a constructor on the object. You can override the init method and perform your own object initialization. The compiler in Objective-C is very different from Java compilers. A lot of things (like calling methods) are first resolved at runtime in objective C. It basically means that because your code compile doesn't mean it works at all. Welcome to the wonderful C/Objective C World! :-) – EsbenB Jun 29 '12 at 10:52
  • 1
    @Felix: *Is it because C is more machine-oriented?* No, it's because Objective C methods are bound at run time. +alloc and -init have no special significance as far as the compiler is concerned. It's the runtime and your code that gives those methods the meaning of allocation and initialisation, not the compiler. – JeremyP Jun 29 '12 at 11:31
  • thanks @Cipramill & @JeremyP for the explanations. That was quite helpful for my understanding. Well, for the solution of my problem: I added the init methods but i still got an empty array back. Then I moved the method call in `ProjectTable.m` from `initWithStyle` to `viewDidLoad` and it worked. – Felix Jun 29 '12 at 13:01
0

First: always call alloc and init to create an object. Second: You don't return the mutable array in your class method. Add a return mockProjects; statement at the end

Francesco
  • 1,840
  • 19
  • 24