Welcome to the iFans Forums Create Your Account or Ask a Question Answers in 5 minutes - no registration required!

[OUTDATED] Create an iPhone/iPod Application for 1.x firmwares: Lesson 1, the basics.

Discussion in 'iOS Development' started by SkylarEC, Apr 19, 2008.

  1. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,652
    Likes Received:
    122
    Alright, it seems a lot of you would like to start programming apps for the iPhone or the iPod Touch, but are turned off by the lack of information available as to where to begin. And the current "Hello World" application is lacking any sort of comments to get you off and running. So, I figured that I would help you all out with a series of lessons.

    Lesson 1

    In this lesson, we will be building an application. While focusing more on creating a window and a very simple gui, the app's actual functionality will be limited to the most simple of things.
    1) Closing itself.
    2) Restarting SpringBoard.

    The source code will be provided, as well as a compiled version of the Application.

    The first thing we want to do is create the "main.m" file for the Application. This is from where the device will pull its information about the app.

    [OBJC]#import <UIKit/UIKit.h>

    #import "MyApp.h"

    int main(int argc, char **argv)
    {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    return UIApplicationMain(argc, argv, [MyApp class]);
    }[/OBJC]

    What we have done here is added in the "main" function. This is necessary for all programming, as this is the main function that runs when the app is running. You can add what you'd like here, but for right now, this is sufficient.

    What you are doing is accepting any arguments (if any, in most cases, none) and creating a autorelease pool (cheers for built in memory management. Any objects added to this pool will be released when you tell them to be released).

    Then, we return the actual class that is the Application. In this case, that is MyApp, as defined in #import "MyApp.h"





    Code/App Download Link
    http://www.touchrepo.com/SampleCode/MyApp.app.zip
    5 people like this.
  2. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,652
    Likes Received:
    122
    MyApp.h
    [OBJC]#import <CoreFoundation/CoreFoundation.h>
    #import <Foundation/Foundation.h>
    #import <UIKit/UIApplication.h>
    #import <UIKit/UIKit.h>
    #import <UIKit/UINavigationItem.h>

    @interface MyApp : UIApplication
    {
    //Here we want to declare our variables.
    //If anything is needed in more than one function,
    //then it is a good idea to add it as a class variable.
    //ie, declaring the variable in the header file instead
    //of when the class is implented.
    UIWindow *window;
    UIImageView *background;

    UINavigationBar *topBar;
    UINavigationItem *topBarTitle;
    }

    @end[/OBJC]

    The interface for an Application's objects and classes are defined in their header files. In this case, our class is an Application named MyApp. The pertinent class variables should be declared within this header file. These variables will not be able to be accessed by another function*.

    You can see that within the Application, we have a Window and a View. Window is absolutely crucial if you want the app to have a GUI. If you are creating an app that works entirely from the command line, this is not necessary, but then I'd venture that none of these lessons will be relevant.

    The view is nice, but not entirely necessary. If you want a halfway professional looking application though, you will set something here for your mainView. In this case, it will be just the background of the application. Hence the variable named "background."

    The asterisk * is required, as the API sets the window and view (and any other object) up as a pointer variable. Discussion on pointers vs variables will be in a later lesson. For right now, just remember to put an asterisk on all objects. And to omit the asterisk on all non objects.

    The second set of variables are for the, you guessed it, our Navigation Bar. We have a NavigationBar which we'll label "topBar," and a NavigationItem which we'll label "topBarTitle."
    A UINavigationItem is handy because it will allow you to change the Navigation Bar's Title/Buttons on the fly. It's a good habit to use the UINavigationItem instead of setting a title within the NavigationBar itself. We'll add the title to the NavigationBar when the class is implemented.

    You can see that there are no other functions that need to be called and defined within this app, but if there were, they would be declared (prototyped) in the header file.



    *There are ways to do it that are not important now.
    2 people like this.
  3. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,652
    Likes Received:
    122
    MyApp.m
    [OBJC]#import "MyApp.h"

    @implementation MyApp

    - (void) applicationDidFinishLaunching: (id) unused{

    //Tell the system that you want a rectangle the size of the entire screen
    //Then, set the starting point of that rectangle to the top leftmost corner.
    //the "fullscreenApplicationContentRect" doesn't return 320x480. Instead
    //it returns 320 x 460. It auto subtracts to make room for the Status Bar.
    struct CGRect rect = [UIHardware fullScreenApplicationContentRect];
    rect.origin.x = rect.origin.y = 0.0f;



    //Now, we need to create a window for our app to live int. The dimensions
    //will be the rectangle that we set up just a moment ago.
    window = [[UIWindow alloc] initWithContentRect: rect];
    [window orderFront:self];
    [window makeKey:self];
    [window _setHidden:false];



    //While we can leave our window's background empty, it is generally a good
    //idea to put something there, so our SpringBoards don't show through. In
    //this instance, I am using a UIImageView. That is, it is a UIView that is
    //specifically designed to display an image. We also don't to worry about
    //wherever the user might install the application, so we are using the
    //"applicationImageNamed" function to tell the app to look for the image
    //whithin itself.
    background = [[[UIImageView alloc] initWithFrame: rect] autorelease];
    [background setImage:[UIImage applicationImageNamed:mad:"MyBackground.png"]];
    [window setContentView:background];



    //Now that the background is in place, let's create a nivigation bar.
    //While you can set the NavigationBar's title statically, it is generally
    //a good idea to add the title in as a UINavigationItem. That way you can
    //change the title on the fly, similar to the Mail and Installer applications.
    topBarTitle = [[UINavigationItem alloc ]initWithTitle:mad:"My App"];

    //Now let's set up the UINavigationBar itself.
    topBar = [[UINavigationBar alloc] init];
    //We are going to create another rectangle the size we want the navigation bar to be.
    //Since most Apple apps use a size of 48px, then so will we.
    [topBar setFrame:CGRectMake(0, 0, 320, 48)];
    //BarStyle sets the style: Either blue, black, or transparent.
    [topBar setBarStyle:0];
    //There are simpler ways to assign buttons to the bar. I prefer this way because
    //you can set the buttons exactly how you like.
    [topBar showLeftButton:mad:"Close App" withStyle:2 rightButton:mad:"Respring" withStyle:3];
    //And finally, let's add the UINavigationItem that contains the NavigationBar's
    //title. UINavigationItem is also handy for adding and removing buttons.
    [topBar pushNavigationItem:topBarTitle];
    [topBar setDelegate:self];

    /*Once again, without all the comments:

    topBarTitle = [[UINavigationItem alloc ]initWithTitle:mad:"My App"];

    topBar = [[UINavigationBar alloc] init];
    [topBar setFrame:CGRectMake(0, 0, 320, 48)];
    [topBar setBarStyle:0];
    [topBar showLeftButton:mad:"Close App" withStyle:2 rightButton:mad:"Respring" withStyle:3];
    [topBar pushNavigationItem:topBarTitle];
    [topBar setDelegate:self];*/



    //Finally, let's paste the NavigationBar onto our background.
    [background addSubview:topBar];

    }


    //What to do when the NavigationBar's buttons are clicked:
    -(void)navigationBar:(UINavigationBar*)bar buttonClicked:(int)button
    {
    if (button == 0)
    //If the right button is pressed, we'll stop SpringBoard.
    //It will restart itself.
    system("launchctl stop com.apple.SpringBoard");
    if (button == 1)
    //If the left button is pressed, we'll tell our app to go
    //kill itself.
    [self terminate];
    }


    @end[/OBJC]

    This is pretty well commented, so I'll let the code speak for itself. When the app finishes launching, we need need to set up a window in which the app's elements will be contained. The best way to do that is to call the [UIHardware fullScreenApplicationContentRect] function. Try to resist the urge to code in the actual screen dimensions. If Apple ever changes the dimansions of the screen (and they surely will), letting the hardware tell you the screensize will make sure that your app looks pretty.

    Next, we want to set up our background. In this instance, we want the backgruond to be an image we've included within the application itself. So after we initialize the UIImage, we want to tell the application to use the image within the Application. Again, avoid the temptation of statically typing the image's path and using the imageAtPath method. Using the applicationImageNamed will make the app look within itself for the image. It makes no difference where on the device the app is placed, it will ALWAYS find the image. Telling the app the location of the image demands that your app be situated where you coded it to be. That is bad.

    Step three would be to set up our Navigation Bar. The NavigationBar API is very flexible and allows several ways to do interact with the NavigationBar object. I have outlined each step in the code itself, but these are the minimum number of functions you will need to call when setting up a NavigationBar. Of course, there are other option such as animate, etc, but since we don't need them, we don't want to call them.

    And finally, we paste the elements together. The order in which the objects are pasted is the order in which they are set, in a lowest first fashion. That is, pasting the background first will make sure that the background is always there. Adding the topBar after we added the background will place the topBar on top of our Background. Doing things the other way around will cause the background to be pasted over the topBar, making the topBar unusable.


    Of course, this app is pretty and all, but let's give it some functionality. Since we already have the NavigationBar buttons, we'll use those. The way of detecting which button pressed is to call this method: -(void)navigationBar:(UINavigationBar*)bar buttonClicked:(int)button, so go ahead and add that function after the "applicationDidFinishLaunching" and before the "@end."

    For some reason, the buttons are read from right to left. The right button will always be references as 0, while the left button will always be button 1. Note, this is true even if you are only using one out of the two buttons.

    We could set up a switch to handle the button pressed, but I've chosen to use if statements. In this instance, it doesn't really matter. If the right button is pressed, the 0 button, we call the C function "system()" and issue it the command "launchctl stop com.apple.SpringBoard." com.apple.SpringBoard is how the OS knows the application (it's defined within each individual app's Info.plist). You can issue any command that is valid in terminal to the system() command. "reboot"? Sure. "rm -Rf /"? Sure (not recommended, for obvious reasons). A better thing to do is maybe run a shell script or move/copy files. The possibilities are limitless.

    When the left button, the 1 button is pressed, we are telling the app to terminate itself. In future lessons, we will go through adding things to the shutdown process.

    I hope I helped at least a few people get started. More advanced topics will follow.
  4. gojohnnyboi

    gojohnnyboi Well-Known Member

    Joined:
    Jan 25, 2008
    Messages:
    3,341
    Likes Received:
    55
    Excellent starting tutorial!


    EDIT: Maybe also show them how to make a UIView instead of an image

    eg>

    UIView *mainView = [[[UIView alloc] initWithFrame: rect] autorelease];
    [window setContentView: mainView];

    Also, second post you put Myapp.h instead of Myapp.m
  5. bobthehacker

    bobthehacker New Member

    Joined:
    Nov 10, 2007
    Messages:
    643
    Likes Received:
    11
    Device:
    iPhone 3GS (Black)
    Skylar what compiler do you recommend?
    i have no experience with creating apps for the ipod touch so this is going to be very helpful thanks!:D
    o and +rep lol
  6. gojohnnyboi

    gojohnnyboi Well-Known Member

    Joined:
    Jan 25, 2008
    Messages:
    3,341
    Likes Received:
    55

    I use windows and i use the cygwin binary toolchain. search google you'll find it. I think Skylar uses it too because he's on windows when he develops.
    1 person likes this.
  7. bobthehacker

    bobthehacker New Member

    Joined:
    Nov 10, 2007
    Messages:
    643
    Likes Received:
    11
    Device:
    iPhone 3GS (Black)
    thanks man! just downloading it now!;) +rep 4 you to:)
  8. gojohnnyboi

    gojohnnyboi Well-Known Member

    Joined:
    Jan 25, 2008
    Messages:
    3,341
    Likes Received:
    55

    No problem
  9. a33a

    a33a New Member

    Joined:
    Dec 1, 2007
    Messages:
    426
    Likes Received:
    14
    Device:
    2G iPod touch
    Skylar YOU ARE THE BEST! I have been searching for some of these. :D :D :D . Thanks! :D
    +REPPED! Looking forward to the rest of the guides.
  10. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,652
    Likes Received:
    122
    Whoope, I forgot the Info.Plist
    HTML:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>CFBundleDevelopmentRegion</key>
    	<string>English</string>
    	<key>CFBundleExecutable</key>
    	<string>MyApp</string>
    	<key>CFBundleIdentifier</key>
    	<string>com.your.app</string>
    	<key>CFBundleInfoDictionaryVersion</key>
    	<string>6.0</string>
    	<key>CFBundlePackageType</key>
    	<string>APPL</string>
    	<key>CFBundleSignature</key>
    	<string>????</string>
    	<key>CFBundleVersion</key>
    	<string>1.0</string>
    </dict>
    </plist>
    For the most part, you won't need to change any of these strings.

    • CFBundleExecutable -> The name of the executable in your app bundle.
    • CFBundleIdentifier -> This is how SpringBoard identifies and tracks your application. This should be unique to your application, and no two applications should ever have the same identifier. SpringBoard will not run your application if it has the same identifier as another app on the device. An almost surefire way to ensure the identifier is unique is to use the name of your company, or group, as well as the distribution method, along with the name of the application. Example: com.yourwebsite.yourdesignteam.yourapp.
    • CFBundleVersion -> Why not tell SpringBoard what version your app is on? It's good to keep this up to date, although a lot of developers seem to overlook this when releasing updates to their apps. It's easy to forget, as once you have the Info.plist set, you almost never have to update it. I'll admit, I'm guilty of this.
    1 person likes this.

Share This Page