Lab 1: ChatBot

The goal of this lab is for you to create a "chat bot" that can perform some useful commands.

You will do this by modifying a premade project, subclassing a simplistic bot to create a more complicated one.

Part 0 — Getting started

To do this lab, you'll need to download the prebuilt ChatBot framework. Open it in Xcode to get started.

Part 1 — Making the subclass

  1. Create a New File… using the File menu. Choose Objective-C Class from the Cocoa category. This will create a new class, representing your chat bot.
  2. Name it XXChatBot.m, with your initials instead of XX. Xcode will automatically fill in a basic header and implementation file for the class XXChatBot (with your initials instead of XX, of course).
  3. Change the superclass for XXChatBot from NSObject to CBChatBot, the class of the simple bot which is currently installed.
  4. Make sure you #import "CBChatBot.h" at the top of the header file, since you are subclassing CBChatBot.
  5. Before you can change anything else, you need to switch CBChatController to use your custom bot. To do this, first open CBChatController.m. The file uses CBChatBot in two places, #import "CBChatBot.h" and bot = [[CBChatBot alloc] init];. Replace CBChatBot with your bot's class name.
  6. Rebuild the project (Build and Run in the Build menu) and make sure there are no errors. It should run the same as before — your bot should inherit all functionality from its superclass, CBChatBot. If there are any errors, check to see that you have done the above steps correctly. You can see any errors by clicking on the red icon in the bottom right of the Xcode window.

Part 2 — Redefining methods

  1. First, let's change the screen name of our bot from "default bot" to something more interesting.
  2. Pick any screen name you'd like for your bot.
  3. To find out the screen name, the program calls [XXChatBot screenName]; in order to change the screen name, you must redefine the + (NSString *)screenName method. Note that it is a class method, which is why it begins with a plus sign (the screen name cannot depend on any internal object state).
  4. In XXChatBot.m, add a definition for + (NSString *)screenName which simply returns the name you've chosen as an NSString *. You can see an example implementation in CBChatBot.m. Remember, to build an NSString, put your @"text in a pair of double quotes preceded by an at sign".
  5. Rebuild the project and see if your new screen name shows up.

Part 3 — Saying "hello"

  1. Now you'd probably like to have your bot say something interesting.
  2. To do this, you must redefine the - (void)respondToChatMessage:(NSString *)chatMessage method in your subclass. Add a definition for this method in your implementation file.
  3. The first thing to make your bot do is respond to greetings. Specifically, when you say "hello," you'd like to have your bot say "hello" back.
  4. As a first step, make your bot say "hello" no matter what you said to it. To do this, add a call to sendMessage:, which is defined in the superclass, CBChatBot. Pass the argument @"hello" (so that it says hello). This method call will look something like [self sendMessage:@"hello"].
  5. Rebuild the project and test this addition.
  6. Now make your bot only send the message when you say @"hello". The text you sent is passed into the method as the string chatMessage. To see whether two objects are equal, use - (BOOL)isEqual:(id)other (if you're interested, here's why you can't just use ==). Use this method with an if statement (if (condition) { code }) to execute your earlier code only when the chatMessage is @"hello".
  7. Rebuild and make sure this addition works, too. Type "hello" and see if it responds, then type something else and make sure it doesn't respond.

Part 4 — Date and time

  1. Now your job is to make the bot reply with the date and time when someone types "date".
  2. + (NSDate *)date is the method to get the current date and time. It is a class method, so you must send it to the NSDate class directly.
  3. To turn a date into a string, you can use the - (NSString *)description method.
  4. Test your code once you're done.

Part 5 — Remember and recall

  1. Another useful feature for a chat bot is the ability to remember important information.
  2. It would be nice to say "remember buy milk at grocery" and, later, say "recall" to retrieve this information.
  3. To implement this feature, you must add an instance variable to your class, so that it can store this data across calls to the respondToChatMessage: method. In your XXChatBot.h file, add an instance variable of type NSString * called rememberedString.
  4. Now, instead of activating when the entire message is "remember", the code should activate when the message begins with "remember". The method on NSString to do this is called - (BOOL)hasPrefix:(NSString *)prefixString.
  5. To store the message in the rememberedString variable, you must call retain on the message string. Otherwise Objective-C may deallocate it before you recall it later. Note that this leaks memory, but we won't worry about that now. Your code will look something like this: rememberedString = [chatMessage retain]; (if you're curious about retain and feel like reading ahead, check out the Memory Management Programming Guide for Cocoa).
  6. Now implement the recall feature. Your bot should reply with the remembered string when you say "recall."
  7. Test your code once you're done.

Part 6 — Timers and selectors

  1. The last feature for this chat bot will be a timer. Here's the idea: when you say "timer N", the bot will wait N seconds, then say "ding!" For example, "timer 6" will wait 6 seconds.
  2. NSTimer is the Cocoa timer class; take a minute to browse its documentation.
  3. NSTimer has a long, but useful, class method + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)yesOrNo. You should read the documentation about using timers to see how to use it.
  4. Let's go over the arguments one at a time.
    1. scheduledTimerWithTimeInterval:(NSTimeInterval)ti — the first argument is an NSTimeInterval, a time duration in seconds.
    2. target:(id)target — when the timer fires, it sends a message to the target specified here.
    3. selector:(SEL)selector — and this is the message it sends. This pattern of target and selector appears everywhere in Cocoa. To specify a method name, use the syntax
      @selector(nameOfMethod:includingArguments:)
      which gives you a value of type SEL.
    4. userInfo:(id)userInfo — sometimes, especially if you have more than one timer, it's useful to pass extra data around. When the timer calls the selector on its target, it will pass your userInfo data along. In this lab, though, you should just pass in nil.
    5. repeats:(BOOL)yesOrNo — if you pass YES, the timer will keep firing at the time interval you specified. If you pass NO it will fire only once. Pretty straightforward.
  5. To get the time interval from the chatMessage string (say, "timer 200"), we need to cut off the beginning characters (leaving just the "200"). The NSString method - (NSString *)substringFromIndex:(NSUInteger)index is what you want here (NSUInteger just means a positive number).
  6. You now have an NSString containing the digits of a number — what you really wanted was a time interval. Fortunately, [string floatValue] will return the floating-point numeric value of such a string (NSTimeInterval is a C floating-point number type).
  7. You still need to specify what happens once the timer triggers. The timer will call any method you give it; define a new method called - (void)timerTriggered:(NSTimer *)timer in your XXChatBot class for the timer to call. When called, it should output, "ding!"
  8. Since timerTriggered: is a method defined on the chat bot object, the target for the timer method will be self.
  9. The selector will be the timerTriggered: method — in code, this looks like @selector(timerTriggered:).
  10. Your timer shouldn't repeat, so pass in NO for repeats.
  11. Finally, write your call to [NSTimer scheduledTimerWithTimeInterval:___ target:___ selector:___ userInfo:nil repeats:___].
  12. Make sure your code runs only when the user enters a message starting with "timer". To do this, use the hasPrefix: method on NSString, just like before.
  13. Test your new feature to make sure it works. If it does, congratulations! You've finished lab 1. You can experiment with other features if you want. Holding down option and double-clicking on class and method names in Xcode will bring up the documentation browser, which will give you lots of useful information on that class, method, or whatever.