Sunday, 25 August 2013

Basics of iOS

The term "iOS" was originally know as "iPhone OS" and was introduced in 2007 along with the first iPhone hardware device Apple released. It was the term used to describe the software that would operate the iPhone and is derived from the term "OS X", which is how Apple describes its "operating system" for its Macintosh computers. The "X" stands for 10 which is the newest version of the computer software Apple created to operate the desktop and laptop computers they design. The "iOS" platform is a mobile-device-based software system that works like a computer system, but on mobile devices like portable phones. It is designed to be smaller, faster and use less power. It also has a "touch" friendly user interface so it works better when a finger is used to interface with the system instead of a mouse or stylus that has been used in the past to interact with operating systems. The iPhone has run on iOS since its release in 2007.


Getting Started

  • Linux/FreeBSD: Install GNUStep
    • In order to build GNUstep applications one must first execute the GNUstep.sh file in /usr/GNUstep/System/Makefiles/GNUstep.sh. This path depends on your system. Some put it in /usr, some /usr/lib, some /usr/local. If your shell is a csh/tcsh based shell, you'll want to execute GNUStep.csh instead. It's recommended that you put this script in your .bashrc or .cshrc.
  • Mac OS X: Install XCode
  • Windows NT 5.X: Install cygwin or mingw and then install GNUStep

 

Creating Classes

@interface

    Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
    Fraction.h

    #import <Foundation/NSObject.h>

    @interface Fraction: NSObject {
        int numerator;
        int denominator;
    }

    -(void) print;
    -(void) setNumerator: (int) n;
    -(void) setDenominator: (int) d;
    -(int) numerator;
    -(int) denominator;
    @end


    NSObject: Short for NeXTStep Object. Although this is less meaningful today since it's really OpenStep.
    Inheritance is specified as Class: Parent, as seen with Fraction: NSObject.
    Instance variables go between @interface Class: Parent { .... }
    No access is set (protected, public, private). Default is protected. Setting the access will be shown later
    Instance methods follow after the member variables. The format is: scope (returnType) methodName: (parameter1Type) parameter1Name;
        scope refers to class or instance. instance methods begin with - class level methods begin with +
    Interface ends with @end


@implementation

    Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
    Fraction.m

    #import "Fraction.h"
    #import <stdio.h>

    @implementation Fraction
    -(void) print {
        printf( "%i/%i", numerator, denominator );
    }

    -(void) setNumerator: (int) n {
        numerator = n;
    }

    -(void) setDenominator: (int) d {
        denominator = d;
    }

    -(int) denominator {
        return denominator;
    }

    -(int) numerator {
        return numerator;
    }
    @end

    @implementation ClassName starts the implementation @end ends it
    All the defined methods are implemented very simlar to how they are declared in the interface

 

 --------------------------------------------------------------------------------

 

 

 Piecing it together

        Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
        main.m

        #import <stdio.h>
        #import "Fraction.h"

        int main( int argc, const char *argv[] ) {
            // create a new instance
            Fraction *frac = [[Fraction alloc] init];

            // set the values
            [frac setNumerator: 1];
            [frac setDenominator: 3];

            // print it
            printf( "The fraction is: " );
            [frac print];
            printf( "\n" );

            // free memory
            [frac release];

            return 0;
        }

        output

        The fraction is: 1/3

        Fraction *frac = [[Fraction alloc] init];
            There are several important things in this one line.
            The way methods in Objective-C are called is [object method], which is similar to object->method() in C++
            Objective-C doesn't have value types, so there is nothing similar to C++'s: Fraction frac; frac.print();. You always deal with objects as pointers in Objective-C.
            What this line is really doing is two things: [Fraction alloc] is calling the alloc method on the Fraction class. This is similar to mallocing memory, because that is all that is done in this operation.
            [object init] is the constructor call, which initializes any variables in the object. This method is called on the instance returned from [Fraction alloc]. This operation is so common it's usually just done in one line as Object *var = [[Object alloc] init];
        [frac setNumerator: 1] is quite simple. It's calling the setNumerator method on frac, and passing it the parameter 1.
        Like every c variant, there's a construct for freeing memory. This is done via release, which is inherited from NSObject. This method will be explainted in greater detail later.

The details...

    Multiple Parameters
        Up until this point I haven't showed any way to specify multiple parameters. It's not as intuitive at first, but it's syntax is a welcome addition from Smalltalk
        Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
        Fraction.h

        ...
        -(void) setNumerator: (int) n andDenominator: (int) d;
        ...

        Fraction.m

        ...
        -(void) setNumerator: (int) n andDenominator: (int) d {
            numerator = n;
            denominator = d;
        }
        ...

        main.m

        #import <stdio.h>
        #import "Fraction.h"

        int main( int argc, const char *argv[] ) {
            // create a new instance
            Fraction *frac = [[Fraction alloc] init];
            Fraction *frac2 = [[Fraction alloc] init];

            // set the values
            [frac setNumerator: 1];
            [frac setDenominator: 3];

            // combined set
            [frac2 setNumerator: 1 andDenominator: 5];

            // print it
            printf( "The fraction is: " );
            [frac print];
            printf( "\n" );

            // print it
            printf( "Fraction 2 is: " );
            [frac2 print];
            printf( "\n" );

            // free memory
            [frac release];
            [frac2 release];

            return 0;
        }

        output

        The fraction is: 1/3
        Fraction 2 is: 1/5

        The method is actually called setNumerator:andDenominator:
        Additional parameters are added the same was as the 2nd, such that you'd have method:label1:label2:label3: and you'd call it with [obj method: param1 label1: param2 label2: param3 label3: param4]
        Labels are optional. It's possible to have a method named method:::. This is done by simply not specifing label names, but just a : to separate the parameters. This is however not advised.
    Constructors
        Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
        Fraction.h

        ...
        -(Fraction*) initWithNumerator: (int) n denominator: (int) d;
        ...

        Fraction.m

        ...
        -(Fraction*) initWithNumerator: (int) n denominator: (int) d {
            self = [super init];

            if ( self ) {
                [self setNumerator: n andDenominator: d];
            }

            return self;
        }
        ...


        main.m

        #import <stdio.h>
        #import "Fraction.h"

        int main( int argc, const char *argv[] ) {
            // create a new instance
            Fraction *frac = [[Fraction alloc] init];
            Fraction *frac2 = [[Fraction alloc] init];
            Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

            // set the values
            [frac setNumerator: 1];
            [frac setDenominator: 3];

            // combined set
            [frac2 setNumerator: 1 andDenominator: 5];

            // print it
            printf( "The fraction is: " );
            [frac print];
            printf( "\n" );

            printf( "Fraction 2 is: " );
            [frac2 print];
            printf( "\n" );

            printf( "Fraction 3 is: " );
            [frac3 print];
            printf( "\n" );

            // free memory
            [frac release];
            [frac2 release];
            [frac3 release];

            return 0;
        }

        output

        The fraction is: 1/3
        Fraction 2 is: 1/5
        Fraction 3 is: 3/10

        @interface declaration is identical to a regular function
        @implementation shows a new keyword: super

            Similar to Java, Objective-C only has one parent class.
            Accessing it's super constructor is done through [super init] and this is required for proper inheritance.
            This returns an instance which you assign to another new keyword, self. Self is similar to this in Java and C++.
        if ( self ) is the same as if ( self != nil ) to make sure that the super constructor successfully returned a new object. nil is Objective-C's form of NULL from C/C++. This is gotten from including NSObject.
        After you've initialized the varialbes, you return yourself with return self;
        The deafult constructor is -(id) init;
        Constructors in Objective-C are technically just "init" methods, they aren't a special construct like they are in C++ and Java.
    Access Privledges
        The default access is @protected
        Java implements this with public/private/protected modifiers infront of methods and variables. Objective-C's approach is much more similar to C++'s for instance variables
        Access.h

        #import <Foundation/NSObject.h>

        @interface Access: NSObject {
        @public
            int publicVar;
        @private
            int privateVar;
            int privateVar2;
        @protected
            int protectedVar;
        }
        @end

        Access.m

        #import "Access.h"

        @implementation Access
        @end

        main.m

        #import "Access.h"
        #import <stdio.h>

        int main( int argc, const char *argv[] ) {
            Access *a = [[Access alloc] init];

            // works
            a->publicVar = 5;
            printf( "public var: %i\n", a->publicVar );

            // doesn't compile
            //a->privateVar = 10;
            //printf( "private var: %i\n", a->privateVar );

            [a release];
            return 0;
        }


        output

        public var: 5

        As you an see, instead of private: [list of vars] public: [list of vars] like in C++, it's just @private, @protected, etc.
    Class level access
        Often it's nice to have class level variables and functions, for instance when keeping track of the # of times an object has been instanciated.
        ClassA.h

        #import <Foundation/NSObject.h>

        static int count;

        @interface ClassA: NSObject
        +(int) initCount;
        +(void) initialize;
        @end

        ClassA.m

        #import "ClassA.h"

        @implementation ClassA
        -(id) init {
            self = [super init];
            count++;
            return self;
        }

        +(int) initCount {
            return count;
        }

        +(void) initialize {
            count = 0;
        }
        @end

        main.m

        #import "ClassA.h"
        #import <stdio.h>

        int main( int argc, const char *argv[] ) {
            ClassA *c1 = [[ClassA alloc] init];
            ClassA *c2 = [[ClassA alloc] init];

            // print count
            printf( "ClassA count: %i\n", [ClassA initCount] );
           
            ClassA *c3 = [[ClassA alloc] init];

            // print count again
            printf( "ClassA count: %i\n", [ClassA initCount] );

            [c1 release];
            [c2 release];
            [c3 release];
           
            return 0;
        }


        output

        ClassA count: 2
        ClassA count: 3

        static int count = 0; This is how the class variable is declared. This is not the ideal place for such a variable. A nicer solution would have been like Java's implementation of static class variables. However this works
        +(int) initCount; This is the actual method that returns the count. Notice the subtle difference. Instead of using a - infront of the type, a + is used. The + denotes a class level function.
        Accessing the variable is no different than member variables, as seen by count++ in the constructor of ClassA.
        The +(void) initialize method is called when Objective-C starts your program, and it's called for every class. This is a good place to initialize class level variables like our count.
    Exceptions
        NOTE: Exception handling is only supported in Mac OS X 10.3
        Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
        CupWarningException.h

        #import <Foundation/NSException.h>

        @interface CupWarningException: NSException
        @end

        CupWarningException.m

        #import "CupWarningException.h"

        @implementation CupWarningException
        @end

        CupOverflowException.h

        #import <Foundation/NSException.h>

        @interface CupOverflowException: NSException
        @end

        CupOverflowException.m

        #import "CupOverflowException.h"

        @implementation CupOverflowException
        @end

        Cup.h

        #import <Foundation/NSObject.h>

        @interface Cup: NSObject {
            int level;
        }

        -(int) level;
        -(void) setLevel: (int) l;
        -(void) fill;
        -(void) empty;
        -(void) print;
        @end

        Cup.m

        #import "Cup.h"
        #import "CupOverflowException.h"
        #import "CupWarningException.h"
        #import <Foundation/NSException.h>
        #import <Foundation/NSString.h>

        @implementation Cup
        -(id) init {
            self = [super init];

            if ( self ) {
                [self setLevel: 0];
            }

            return self;
        }

        -(int) level {
            return level;
        }

        -(void) setLevel: (int) l {
            level = l;

            if ( level > 100 ) {
                // throw overflow
                NSException *e = [CupOverflowException
                    exceptionWithName: @"CupOverflowException"
                    reason: @"The level is above 100"
                    userInfo: nil];
                @throw e;
            } else if ( level >= 50 ) {
                // throw warning
                NSException *e = [CupWarningException
                    exceptionWithName: @"CupWarningException"
                    reason: @"The level is above or at 50"
                    userInfo: nil];
                @throw e;
            } else if ( level < 0 ) {
                // throw exception
                NSException *e = [NSException
                    exceptionWithName: @"CupUnderflowException"
                    reason: @"The level is below 0"
                    userInfo: nil];
                @throw e;
            }
        }

        -(void) fill {
            [self setLevel: level + 10];
        }

        -(void) empty {
            [self setLevel: level - 10];
        }

        -(void) print {
            printf( "Cup level is: %i\n", level );
        }
        @end

        main.m

        #import "Cup.h"
        #import "CupOverflowException.h"
        #import "CupWarningException.h"
        #import <Foundation/NSString.h>
        #import <Foundation/NSException.h>
        #import <Foundation/NSAutoreleasePool.h>
        #import <stdio.h>

        int main( int argc, const char *argv[] ) {
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
            Cup *cup = [[Cup alloc] init];
            int i;

            // this will work
            for ( i = 0; i < 4; i++ ) {
                [cup fill];
                [cup print];
            }

            // this will throw exceptions
            for ( i = 0; i < 7; i++ ) {
                @try {
                    [cup fill];
                } @catch ( CupWarningException *e ) {
                    printf( "%s: ", [[e name] cString] );
                } @catch ( CupOverflowException *e ) {
                    printf( "%s: ", [[e name] cString] );
                } @finally {
                    [cup print];
                }
            }

            // throw a generic exception
            @try {
                [cup setLevel: -1];
            } @catch ( NSException *e ) {
                printf( "%s: %s\n", [[e name] cString], [[e reason] cString] );
            }

            // free memory
            [cup release];
            [pool release];
        }

        output

        Cup level is: 10
        Cup level is: 20
        Cup level is: 30
        Cup level is: 40
        CupWarningException: Cup level is: 50
        CupWarningException: Cup level is: 60
        CupWarningException: Cup level is: 70
        CupWarningException: Cup level is: 80
        CupWarningException: Cup level is: 90
        CupWarningException: Cup level is: 100
        CupOverflowException: Cup level is: 110
        CupUnderflowException: The level is below 0

        NSAutoreleasePool is a memory management class. Don't worry about what this does right now.
        Exceptions that are thrown don't have to extend NSException. You can just as easily use an id as well: @catch ( id e ) { ... }
        There is also a finally block, which behaves just like Java's. The contents of a finally block are guaranteed to be called.
        The string as show in Cup.m, @"CupOverflowException", is a constant NSString object. The @ sign is used often in Objective-C to denote extentions to the language. A C string is just like C and C++, "String constant", and is of type char *.
 

 

 

No comments:

Post a Comment