Learning Objective C - Critique?

Associate
Joined
16 Mar 2005
Posts
708
Location
Staffordshire
Hi Chaps

Over the last week or so I've had my head stuck in a couple of Objective-C / iOS Development books. My usual way of learning is read a couple of chapters and then complete the included examples, but try to build on them and maybe go a step further - which I'm sure is how many other people tend to learn best.

Because of work commitments etc, I've not really managed to do too much, but though as I haven't got much to do today - I'd have a lovely day of learning. So, I've read through a few chapters, got an a basic understanding and started to go through the examples. Like I mentioned earlier, I find the best way to get this stuff to stick in my head if to read the book, and then kind of abandon it and try to replicate the examples that I've read through, but using the SDK reference material and Google to work out any problems.

I could do with anyone just checking over my code and just giving there opinion - have I missed something? Is there an easier way to achieve something? I'm just after pointers as I go along really.

The example is a really basic question and answer application - you press a button to get a question and press another button to get an answer.

Here's the code:

Code:
########## --- QuizModel.h --- ##########

@interface QuizModel : NSObject {
	
	NSMutableArray *questions;
	NSMutableArray *answers;
	
	int questionsDone;

}

- (NSInteger)nextQA;

- (NSString *)getQuestion;

- (NSString *)getAnswer;

- (id)init;

@end

########## --- QuizModel.m --- ##########

#import "QuizModel.h"


@implementation QuizModel

- (NSString *) getQuestion {
	return [questions objectAtIndex:[self nextQA]];
}

- (NSString *) getAnswer {
	return [answers objectAtIndex:questionsDone-1];
}

- (int) nextQA {
	if (questionsDone == [questions count]) {
		questionsDone = 0;
	}
	
	return questionsDone++;
}

- (id) init {
	[super init];
	
	questions = [[NSMutableArray alloc] init];
	answers = [[NSMutableArray alloc] init];
	
	[questions addObject:@"Question 1"];
	[answers addObject:@"Answer 1"];
	
	[questions addObject:@"Question 2"];
	[answers addObject:@"Answer 2"];
	
	[questions addObject:@"Question 3"];
	[answers addObject:@"Answer 3"];
	
	return self;
}

@end

Code:
########## --- QuizViewController.h --- ##########

#import <UIKit/UIKit.h>
#import "QuizModel.h"

@interface  QuizViewController : NSObject <UIApplicationDelegate> {
    UIWindow *window;
	
	IBOutlet UILabel *questionsLabel;
	IBOutlet UILabel *answersLabel;
	
	QuizModel *quizObject;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

- (IBAction)showQuestion;

- (IBAction)showAnswer;

@end


########## --- QuizViewController.h --- ##########

#import " QuizViewController.h"

@implementation  QuizViewController

@synthesize window;

#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.
    
	quizObject = [[QuizModel alloc] init];
	
    [self.window makeKeyAndVisible];
	 
    return YES;
}

- (void)dealloc {
    [window release];
    [super dealloc];
}

- (IBAction)showQuestion {
	[questionsLabel setText:(NSString *)[quizObject getQuestion]];
}

- (IBAction)showAnswer {
	[answersLabel setText:(NSString *)[quizObject getAnswer]];
}

@end

Thanks in advance, Chaps.

Martin
 
For your QuizModel object, currently you're allocating within the init: but the object doesn't have a dealloc in which the NSArray pair get released. iOS doesn't have garbage collection.

The questionsDone field is not initialised explicitly and relies on the compiler to zero initialise it.

Also you should use the following construct in the init:

-(id)init {
if( (self=[super init]) ) { // yes that's a single =
initialise things here.
}
return self;
}

-(void)dealloc {
// free resources here
[super dealloc];
}

this calls the super class initialiser and if the super fails to initialise it will return nil. You will then return nil too. Of course you only want to initialise if the super initialises.

Also you don't release the quizObject in the QuizViewController dealloc.


No need to make this super complicated. You could use a persistent store with data binding with a view (such as a customised table view or navigation view) to alternate between questions and answers.
You then use the animation and Quartz2D system to blend between the questions and answers in funky ways.. the options on making this complicated are endless!
 
Last edited:
Hi NickK

I really appreciate your response, it's so much easier getting actual feedback on the code, rather than just trying to guess what is and isn't right.

I totally forgot about garbage collection! I have a book that I'm working from to learn Objective-C and the examples that I've gone through so far are console applications. So I don't think garbage collection is required?

I'm a little confused about the [super init] assignment - why is that done?

Thanks

Martin
 
[super init] is used to initialise the parent super class.

This is a subtlety of the Objective-C class system. Unlike C++ when you alloc a class it doesn't automatically initialise it. So when your parent class is allocated by the system (when you alloc your class), the parent class is not initialised.

Objective-C passes messages. The init message arrives at your class and therefore there's no requirement on the caller to send an init message to each of your parent class objects that have been automatically allocated.

The if statement just protects you from attempting to initialise, perhaps using parent class attributes or methods in the event the parent class fails to initialise.

Console apps still require memory management. That could be a autorelease pool which is the normal method to catch things like NSString etc otherwise you'd need to release the string carefully..
 
Back
Top Bottom