IOS学习笔记1

1. More on Classes

1. Separate Interface and Implementation Files

Fraction.h

//
//  Fraction.h
//  FractionTest
//
//  Created by lgt on 15/7/2.
//  Copyright (c) 2015年 lgt. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Fraction : NSObject
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
-(double) convertToNum;
@end



    The interface file tells the compiler what a Fraction looks like.


Fraction.m

//
//  Fraction.m
//  FractionTest
//
//  Created by lgt on 15/7/2.
//  Copyright (c) 2015年 lgt. All rights reserved.
//

#import "Fraction.h"

@implementation Fraction
{
    int numerator;
    int denominator;
}

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

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

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

-(int) numerator
{
    return numerator;
}

-(int) denominator
{
    return denominator;
}

-(double) convertToNum
{
    if (denominator != 0) {
        return (double) numerator / denominator;
    } else {
        return NAN;
    }
}
@end



main.m


#import "Fraction.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        Fraction *myFraction = [[Fraction alloc] init];
        
        [myFraction setNumerator:1];
        [myFraction setDenominator:3];
        
        NSLog(@"The value of myFraction is:");
        [myFraction print];
    }
}



the output is:


2015-07-02 18:32:00.514 FractionTest[9121:881411] The value of myFraction is:
2015-07-02 18:32:00.515 FractionTest[9121:881411] 1/3



2. Synthesized Accessor Methods


    As of Objective-C 2.0, we can have our setter and getter methods automatically generated for me.

    the first step is to use the @property directive in our interface section to identify our properties.These properties are often named the same as our instance variables, although they don't have to be.

@interface Fraction : NSObject

@property int numerator, denominator;

-(void) print;
-(double) convertToNum;
@end



Note that we no longer include the definitions for our getter and setter methods:numerator, denominator,setNumerator,and setDenominator. We're going to have the Objective-C compiler automatically generate or synthesize these for us.


#import "Fraction.h"

@implementation Fraction

@synthesize numerator, denominator;

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

-(double) convertToNum
{
    if (denominator != 0) {
        return (double) numerator / denominator;
    } else {
        return NAN;
    }
}
@end



    The following line tells the Objective-C compiler to generate a pair of getter and setter methods for each of the two properties, numerator and denominator:


@synthesize numerator, denominator;



just think we have property called x, so after:


@synthesize x



generate a method called x and a setter method called setX.


3. Accessing Properties Using the Dot Operator

    After we use:

@property int numerator, denominator;



when we write:


myFraction.numerator = 1;



it is equal to:


[myFraction setNumerator:1];



when we write:


myFraction.numerator



it is equal to:


[myFraction numerator]



so the test example is:


#import "Fraction.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        Fraction *myFraction = [[Fraction alloc] init];
        
        myFraction.numerator = 1;
        myFraction.denominator = 3;
        
        //[myFraction setNumerator:1];
        //[myFraction setDenominator:3];
        
        NSLog(@"The value of myFraction is:%i/%i", myFraction.numerator, myFraction.denominator);
    }
}



4. Multiple Arguments to Methods


    we could write the code to make multiple arguments to methods:

-(void) setTo: (int) n over: (int) d;



the implement is:


-(void) setTo:(int)n over:(int)d
{
    numerator = n;
    denominator = d;
}



5. The self Keyword


    when we want to invoke a method in the same class, how could we do? we could use self:

@interface ClassA : NSObject
-(void) print;
-(void) invokePrint;
@end

@implementation ClassA

-(void) print
{
    NSLog(@"hello world");
}
-(void) invokePrint
{
    [self print];
}

@end

int main(int argc, char *argv[])
{
    @autoreleasepool {
        ClassA *a = [[ClassA alloc] init];
        
        [a invokePrint];
    }
}
the output is:

2015-07-02 19:08:48.319 FractionTest[9224:889966] hello world

2. Inheritance

1. It All Begins at the Root

    when we write the code:

@interface Fraction : NSObject

@end



the NSObject is parent class, and the Fraction is subclass.


    whenever a new class(other than a new root class) is defined, the class inherits certain things. For example, the(nonprivate) instance variables and the methods from the parent implicitly become part of the new class definition. That means the subclass can access these methods and instance variables, as if they were defined directly within the class definition.

    Note that the instance variables that are to be accessed directly by a subclass must be declared in the interface section.Instance variables declared or synthesized in the implementation section are private instance variables and are not directly accessible by subclasses. Instead, you want to use their explicitly defined or synthesized getter and setter methods to access their values.

example 1: the public variable is inherit

@interface ClassA : NSObject
{
    int x;
}

-(void) initVar;
@end

@implementation ClassA
-(void) initVar
{
    x = 100;
}
@end

@interface ClassB : ClassA
-(void) printVar;
@end

@implementation ClassB

-(void) printVar
{
    NSLog(@"x = %i", x);
}

@end

int main(int argc, char *argv[])
{
    @autoreleasepool {
        ClassB *b = [[ClassB alloc] init];
        
        [b initVar];
        
        [b printVar];
    }
}



    the ClassB instant print the public variable x of ClassA, and the output is:


2015-07-02 20:36:11.951 FractionTest[9306:899284] x = 100



example 2: the synthesize variable is private


@interface ClassA : NSObject

@property int x;
@end

@implementation ClassA
@synthesize x;
@end

@interface ClassB : ClassA
-(void) printVar;
@end

@implementation ClassB

-(void) printVar
{
    //NSLog(@"x = %i", x);
    NSLog(@"x = %i", [self x]);
}

@end

int main(int argc, char *argv[])
{
    @autoreleasepool {
        ClassB *b = [[ClassB alloc] init];
        b.x = 100;
        
        [b printVar];
    }
}



    the output is 100 too, but if we write:


NSLog(@"x = %i", x);



it will occurs an error! because x of ClassA is a private variable.


2. The @class Directive

    now we define XYPoint class:


#import <Foundation/Foundation.h>

@interface XYPoint : NSObject

@property int x, y;

-(void) setX: (int) xVal andY: (int) yVal;

@end



we add an instance variable, called origin like that:



@interface Fraction : NSObject

@property int numerator, denominator;

-(XYPoint *) origin;

-(void) print;
-(double) convertToNum;
-(void) setTo: (int) n over: (int) d;
@end



but there has a question that we don't known what XYPoint is, so we could add:



@class XYPoint;



but if we want to any method of XYPoint, we should add:



#import "XYPoint.h"



so the whole code is:


XYPoint.h


#import <Foundation/Foundation.h>

@interface XYPoint : NSObject

@property int x, y;

-(void) setX: (int) xVal andY: (int) yVal;

@end



XYPoint.m



#import "XYPoint.h"

@implementation XYPoint

@synthesize x, y;

-(void) setX:(int)xVal andY:(int)yVal
{
    x = xVal;
    y = yVal;
}

@end



Rectangle.h



#import <Foundation/Foundation.h>

@class XYPoint;
@interface Rectangle : NSObject

@property int width, height;

-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(int) area;
-(int) perimeter;
@end



Rectangle.m



#import "Rectangle.h"

@implementation Rectangle
{
    XYPoint *origin;
}

@synthesize width, height;

-(void) setWidth:(int)w andHeight:(int)h
{
    width = w;
    height = h;
}

-(void) setOrigin:(XYPoint *)pt
{
    origin = pt;
}

-(int) area
{
    return width * height;
}

-(int) perimeter
{
    return (width + height) * 2;
}

-(XYPoint *) origin
{
    return origin;
}

@end



main.m



#import "Rectangle.h"
#import "XYPoint.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        Rectangle *myRect = [[Rectangle alloc] init];
        XYPoint *myPoint = [[XYPoint alloc] init];
        
        [myPoint setX:100 andY:200];
        [myRect setWidth:5 andHeight:8];
        myRect.origin = myPoint;
        
        NSLog(@"Origin at (%i, %i)", myRect.origin.x, myRect.origin.y);
        
        [myPoint setX:50 andY:50];
        NSLog(@"Origin at (%i, %i)", myRect.origin.x, myRect.origin.y);
    }
}



the output is:



2015-07-02 21:46:04.271 FractionTest[9415:909226] Origin at (100, 200)
2015-07-02 21:46:04.272 FractionTest[9415:909226] Origin at (50, 50)



the question is: why we change the myPoint values, myRect change it's origin too?


    then we look the code:


-(void) setOrigin:(XYPoint *)pt
{
    origin = pt;
}



we find that XYPoint and Rectangle use the values, origin and pt are point to the same memory.



3. Polymorphism, Dynamic Typing, and Dynamic Binding

    Polymorphism enables programs to be developed so that objects from different classes can define methods that share the same name. Dynamic typing defers the determination of the class that an object belongs to until the program is executing. Dynamic binding defers the determination of the actual method to invoke on an object until program execution time.

1. Polymorphism: Same Name, Different Class

    just think that we define class ClassA and ClassB, each class define the print method.so when we write the code:

ClassA *a = [[ClassA alloc] init];
...
[a print]



how the class know which print can be invoked?


    It's simple: The Objective-C runtime knows that a is a ClassA object, so it select the ClassA.print method.

2. Dynamic Binding and the id Type

    id can be used for storing objects that belong to any class. The real power of this data type is exploited when it's used this way to store different types of objects in a variable during the execution of a program.

the example code:

#import "Rectangle.h"
#import "XYPoint.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        id dataValue;
        
        Rectangle *myRect = [[Rectangle alloc] init];
        XYPoint *myPoint = [[XYPoint alloc] init];
        
        dataValue = myRect;
        [dataValue print];
        
        dataValue = myPoint;
        [dataValue print];
    }
}



3. Compile Time Versus Runtime Checking


    Because the type of object stored inside an id variable can be indeterminate at compile time, some tests are deferred until runtime--that is, while the program is executing.

Consider the following sequence of code:

Fraction *f1 = [[Fraction alloc] init];
[f1 setReal: 10.0 andImaginary: 2.5];



but Fraction don't have the method: setReal: andImaginary, so it will occur an warning at compiler:


/Users/lgt/Desktop/FractionTest/main.m:20:13: No visible @interface for 'Fraction' declares the selector 'setReal:andImaginary:'



Now consider the following code sequence:


id f1 = [[Fraction alloc] init];
[f1 setX: 10.0 andY: 2.5];



These lines do not produce a warning message from the compiler because the compiler doesn't know 













你可能感兴趣的:(ios,Objective-C)