views:

865

answers:

4

Hi! I've got a PHP background, but I'm beginning to learn Objective-C, so that I can develop apps for the iPhone. So far things are going pretty well, but I've got a question that I haven't been able to find and answer to yet after googling and mining a number of different forums.

My app has to create a number of views, each with it's own uinque title bar. In order to do this, my code looks something like this for each view:

    xViewController = [ [ XViewController alloc ] init ];
    xNavController = [ [ UINavigationController alloc ]
     initWithRootViewController: xViewController
    ];
    xNavController.tabBarItem = [ [ UITabBarItem alloc ]
     initWithTitle: @"My Info"
     image: [ UIImage imageNamed: @"my_info.png" ]
     tag: 3
    ];

This works, but what I'd like to do is to create a method that will return a nav controller when sent a string as a message, so I don't have to do all this for each view. The issue I am having is that the first line needs to allocate an object based on a class name passed to it as a string (i.e. XViewController needs to be taken from a string passed to the method), but I don't know how to treat a string as a class name. I know it's possible, because the UIApplicationMain() can use a string to call the app delegate class. How can I do it?

I'm sorry if any of this doesn't make sense, I'm still in the early stages of learning a new language!

A: 

Use Objective-C 2.0 Runtime Reference

J-16 SDiZ
+4  A: 

As well as using the runtime, you can do it just using Cocoa-touch methods:

NSString* theClassName = /* assume this exists */
Class theClass = NSClassFromString(theClassName);
NSObject* myObject = [[theClass performSelector:@selector(alloc)] init];
// do something with the new object instance
Jason Coco
Exactly what I'm looking for. Thanks Jason!
JoBu1324
You don't need the performSelector:, you can just write [[theClass alloc] init].
Jon Hess
A: 

If I understand your problem correctly you don't need dynamic classes to make this work. Why not create, for each view controller class, its unique title and image method that just returns the unique title and image for that view controller. Then create a super class for your view controller classes with dummy title and image methods.

Your code above will then look something like this:

- (UINavigationController *)getNavController:(XGenericViewController *)viewController
{
        UINavigationController  *xNavController = [ [ UINavigationController alloc ]
            initWithRootViewController: viewController
        ];
        xNavController.tabBarItem = [ [ UITabBarItem alloc ]
            initWithTitle: [viewController title]
            image: [viewController image]
            tag: 3
        ];

    return [xNavController autorelease];
}
Diederik Hoogenboom
A: 

If you have multiple TableViewCells loaded from NIBs, the code to load the individual NIBs gets ugly if you don't do something with dynamic loading.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // header
    if (indexPath.row == 0) {
     cellHeader *cell = (cellHeader *)[self loadCell:identHeader];
     return cell;

    // load more
    } else if (indexPath.row == lastRow) {
     loadMore *cell = (loadMore *)[self loadCell:identLoadMore];
     return cell;
    }

    // default
    cellDefault *cell = (cellDefault *)[self loadCell:identDefault];
    return cell;
}

- (id)loadCell:(NSString *)className {
    id cell = [tweetsView dequeueReusableCellWithIdentifier:className];

    if (cell == nil) {
     NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:className owner:nil options:nil];

     for (id currentObject in topLevelObjects) {
      if ([currentObject isKindOfClass:[UITableViewCell class]]) {
       cell = currentObject;
       break;
      }
     }
    }

    return cell;
}