iOS開發系列--Objective-C之類和對象

概述

前面已經簡單介紹過ObjC的基礎知識,讓你們對ObjC有個大體的印象,今天將重點解釋ObjC面向對象的特性。ObjC相對於C語言多了面向對象特性,可是ObjC又沒有其餘面嚮對象語言那麼多語法特性,ObjC自己對面向對象進行了精簡。固然這並不表明今天的內容就會少,今天的內容仍是至關多的:java

  1. 類定義
  2. 成員變量
  3. 方法和屬性
  4. self關鍵字
  5. 構造方法
  6. description方法
  7. 繼承

類定義

在C#、Java等其餘高級語言中定義一個類是至關簡單點的,直接一個關鍵字class加一對大括號基本就完成了,可是在ObjC中類的定義相對變化比較大。如今假設須要定義一個Person類框架

在Xcode中添加文件,選擇Cocoa Class 或者Cocoa Touch Class函數

cocoaClass

輸入類名Person,並選擇父類爲NSObjectui

ClassName 默認生成以下兩個文件this

Person.h編碼

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@end

Person.matom

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

@end

在ObjC中定義一個類須要兩個文件.h和.m:spa

  • .h文件:放類的聲明,包括成員變量、屬性和方法聲明(事實上.h文件不參與編譯過程);關鍵字@interface聲明一個類,同時它必須以@end結束,在這兩個關鍵字中間聲明相關成員;在聲明Person類的同時能夠看到它繼承於NSObject,這是ObjC的基類,全部的類最終都繼承於這個類(可是須要注意ObjC中的基類或者根類並不僅有一個,例如NSProxy也是ObjC的基類),因爲這個類在Foundation框架中定義,因此導入了<Foundation/Foundaton.h>(這麼描述的意思是導入Foundation框架中的Foundation.h聲明文件);
  • .m文件:放屬性、方法的具體實現;關鍵字@implementation用於實現某個類,同時必須以@end結尾,在這兩個關鍵字中間實現具體的屬性、方法;因爲.m中使用了Person類,因此須要導入聲明文件「Person.h」;

成員變量

假設在Person類中包含人員姓名(name)、年齡(age)、民族(nation)、身高(height)四個成員變量,同時姓名和年齡兩個成員變量是私有的,身高是公開的,民族則限制爲只有子類能夠訪問。3d

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>//因爲使用了NSObject,因此導入此頭文件

//NSObject是基類,Person實現了NSObject
@interface Person : NSObject{
    /*成員變量必須包含在大括號中
     *注意成員變量不聲明任何關鍵字的話是默承認訪問性@Protected
     *注意在ObjC中不論是自定義的類仍是系統類對象都必須是一個指針,例以下面的_name
     */
    @private
    NSString *_name;//在ObjC中推薦成員變量名以_開頭
    int _age;
    @protected
    NSString *_nation;
    @public
    float height;
}

@end

成員變量定義在.h文件中,同時必須定義在類後面的{}內。成員的可訪問性經過下面三個關鍵字聲明:指針

  • @private 私有成員,只有當前類能夠訪問;
  • @protected 受保護成員,只有當前類或子類能夠訪問(若是沒有添加任何修飾則默認爲@protected);
  • @public 公共成員,全部類都可訪問;

在ObjC中可訪問性修飾符除了這三種,還有一個@package不太經常使用,它相似於C#中的internal在框架內是公共的,可是框架外是私有的(也就是隻能在一個框架內能夠訪問)。那麼既然身高是公共的,外界怎麼訪問呢?

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p=[Person alloc];
        p=[p init];
        //上面兩句代碼能夠直接寫成:Person *p=[[Person alloc] init];
        //還能夠寫成:Person *p=[Person new];
        
        p->height=1.72;
        NSLog(@"height=%.2f",p->height);//結果:height=1.72
    }
    return 0;
}

這裏須要注意幾點:

  • ObjC中全部的對象類型的變量都必須加上「*」,在ObjC中對象其實就是一個指針(例如以前看到的NSString也是如此,可是基本類型不用加」*」);
  • ObjC中使用[]進行方法調用,在ObjC中方法調用的本質就是給這個對象或類發送一個消息;
  • 在ObjC中類的實例化須要兩個步驟:分配內存、初始化;
  • 類的初始化調用了父類的init方法,若是使用默認初始化方法進行初始化(沒有參數),內存分配和初始化能夠簡寫成[Person new];
  • 公共成員的調用使用「->」操做符;

方法和屬性

既然有了上面成員變量,假設如今須要一個對象方法去設置用戶姓名,還需一個類方法打印一些信息。

在ObjC中方法分爲靜態方法和動態方法兩種,動態方法就是對象的方法,靜態方法就是類方法,這一點跟其餘高級語言沒有區別。在ObjC中使用「-」定義動態方法,使用「+」定義靜態方法。若是一個方法在.h中有聲明則該方法是公共方法,若是沒有在.h中聲明直接在.m中定義則該方法是私有方法,外部沒法訪問。

person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>//因爲使用了NSObject,因此導入此頭文件

//NSObject是基類,Person實現了NSObject
@interface Person : NSObject{
    /*成員變量必須包含在大括號中
     *注意成員變量不聲明任何關鍵字的話是@Protected,其餘還有@Private和@Public
     *注意在ObjC中不論是自定義的類仍是系統類對象都必須是一個指針,例以下面的_name
     */
    @private
    NSString *_name;//在ObjC中推薦變量名以_開頭
    int _age;
    @protected
    NSString *_nation;
    @public
    float height;
}

//聲明一個動態方法,沒有返回值
-(void)setName:(NSString *)name;
//聲明一個靜態方法,沒有返回值
+(void)showMessage:(NSString *)info;

@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

//實現一個動態方法
-(void)setName:(NSString *)name{
    _name=name;
}

//實現一個靜態方法
+(void)showMessage:(NSString *)info{
    NSLog(@"%@",info);
}
@end

在ObjC中方法的參數類型、返回值類型須要放到()中,並且參數前必須使用冒號,而且此時冒號是方法名的一部分。固然,上面的方法只有一個參數,假設如今有一個方法能夠同時設置年齡和籍貫,能夠寫成以下形式:

-(void)setAge:(int)age andHeight:(NSString *)nation{
    _age=age;
    _nation=nation;
}

其中andHeight能夠省略不寫,固然爲了保證方法名更有意義建議書寫時加上。

你們都知道在其餘語言中還會常常提到屬性的概念,一般一個成員的訪問不會直接經過成員變量而是經過屬性暴漏給外界。在ObjC中屬性的實現方式其實相似於Java中屬性定義,經過對應的setter和getter方法進行實現。沒錯,上面setName其實就是屬性的setter方法,可是在ObjC中gettter方法一般使用變量名,而不加「get」。下面就看一下年齡屬性的實現

Person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>//因爲使用了NSObject,因此導入此頭文件

//NSObject是基類,Person實現了NSObject
@interface Person : NSObject{
    /*成員變量必須包含在大括號中
     *注意成員變量不聲明任何關鍵字的話是@Protected,其餘還有@Private和@Public
     *注意在ObjC中不論是自定義的類仍是系統類對象都必須是一個指針,例以下面的_name
     */
    @private
    NSString *_name;//在ObjC中推薦變量名以_開頭
    int _age;
    @protected
    NSString *_nation;
    @public
    float height;
}

//聲明一個動態方法,沒有返回值
-(void)setName:(NSString *)name;
//聲明一個靜態方法,沒有返回值
+(void)showMessage:(NSString *)info;

//聲明age的setter、getter方法
-(int)age;
-(void)setAge:(int)age;

@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

//實現一個動態方法
-(void)setName:(NSString *)name{
    _name=name;
}

//私有方法
-(void)setAge:(int)age andHeight:(NSString *)nation{
    _age=age;
    _nation=nation;
}

//實現一個靜態方法
+(void)showMessage:(NSString *)info{
    NSLog(@"%@",info);
}

//實現age的setter、getter方法
-(int)age{
    return _age;
}
-(void)setAge:(int)age{
    _age=age;
}
@en

接下來看一下具體的調用

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p=[Person alloc];
        p=[p init];
        //上面兩句代碼能夠直接寫成:Person *p=[[Person alloc] init];
        //還能夠寫成:Person *p=[Person new];
        
        //成員變量調用
        p->height=1.72;
        NSLog(@"height=%.2f",p->height);//結果:height=1.72
        
        //方法調用
        [p setName:@"Kenshin"];
        
        //屬性調用
        p.age=28; //等價於:[p setAge:28];
        int age=p.age;//等價於:age=[p age];
        NSLog(@"age=%i",age); //結果:age=28
        
    }
    return 0;
}

關於方法的調用在這裏不着重介紹了,咱們能夠看到p.age的調用方式,是否是相似於C#、Java中屬性的調用方式,這就是ObjC中的點語法。其實這種方式調用的本質仍是調用對應的方法進行處理,這麼作的目的只是爲了開發人員書寫方便而已(這就是語法糖的目的)。至於p.age是調用get方法仍是調用set方法徹底取決於當前操做是賦值操做仍是讀取操做。

經過上面的程序咱們能夠看到若是要定義一個屬性,首先須要在.h中聲明其次還要在.m中實現,而定義屬性的代碼基本都是相似的,那麼有沒有簡單的方法呢,其實在ObjC中能夠經過聲明@property,同時經過@synthesize自動生成getter、setter方法(在新版本中甚至甚至都不用經過@synthesize只聲明就可使用)。咱們經過一段代碼來講明這個問題(爲了方便你們查看代碼,在下面的代碼中暫時去掉前面定義的成員變量、屬性等)

Person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject{
    @public
    NSString *birthday;
    NSString *_position;
    NSString *_degress;
}

@property NSString *birthday;

@property NSString *position;

@property NSString *degress;

@property NSString *education;

@property float weight;

-(void)printInfo;
@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

@synthesize birthday;
@synthesize position;
@synthesize degress=_degress;

@synthesize education;

-(void)printInfo{
    NSLog(@"_weight=%.2f",_weight);
    NSLog(@"education=%@",education);
    NSLog(@"_degress=%@",_degress);
}
@end

main.m

//
//  main.m
//  ClassAndObject
//
//  int main(int argc, const char * argv[]) {
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    
    Person *p=[[Person alloc]init];
    p->birthday=@"1987-08-20";
    p.birthday=@"1986-08-08";
    p->_position=@"developer";
    p.position=@"architect";
    
    p.degress=@"undergraduate";
    
    p.education=@"university";
    
    p.weight=60.0;
    
    NSLog(@"p->birthday=%@,p.birthday=%@",p->birthday,p.birthday);
    //結果:p->birthday=1986-08-08,p.birthday=1986-08-08
    
    NSLog(@"p->_position=%@,p.position=%@",p->_position,p.position);
    //結果:p->_position=developer,p.position=architect
    
    NSLog(@"p.weight=%.2f",p.weight);
    //結果:p.weight=60.00
    [p printInfo];
    /*結果:
     _weight=60.00
     education=university
     _degress=undergraduate*/
    
    return 0;
}

上面的代碼雖然簡單,可是幾乎涵蓋全部屬性生成規則。經過上面的代碼咱們能夠看到最簡單的方法就是直接經過@property就能夠聲明一個變量(例如weight屬性),不須要進行實現便可直接使用;還可使用@property聲明再用@synthesize去實現(例如上面的birthday屬性),不只如此在實現的時候還能夠指定實現此屬性時使用哪一個成員變量(例如degress屬性)。在上面的代碼中咱們還看到weight屬性自動生成了一個_weight成員變量,而education生成了一個education屬性,那麼它們生成的規則是什麼呢,這裏總結以下:

  • 若是隻聲明一個屬性a,不使用@synthesize實現:編譯器會使用_a做爲屬性的成員變量(若是沒有定義成員變量_a則會自動生成一個私有的成員變量_a;若是已經定義了成員變量_a則使用自定義的成員變量_a。注意:若是此時定義的成員變量不是_a而是a則此時會自動生成一個成員變量_a,它跟自定義成員變量a沒有任何關係);
  • 若是聲明瞭一個屬性a,使用@synthesize a進行實現,可是實現過程當中沒有指定使用的成員變量(例如上面birthday):則此時編譯器會使用a做爲屬性的成員變量(若是定義了成員變量a,則使用自定義成員變量;若是此時沒有定義則會自動生成一個私有的成員變量a,注意若是此時定義的是_a則它跟生成的a成員變量沒有任何關係);
  • 若是聲明瞭一個屬性a,使用@synthesize a=_a進行實現,這個過程已經指定了使用的成員變量:此時會使用指定的成員變量做爲屬性變量;

有了上面的總結,相信理解上面的代碼並不難,一般在實際開發過程當中咱們要麼直接在@property中聲明不使用@synthesize;要麼使用過程當中指定具體的成員變量。

此外再次強調一下,經過上面的方式定義變量的本質仍是生成對應的gettter、setter方法(只是這個步驟編譯器幫你完成了),若是經過@property定義了屬性,同時在.m中又自定義實現了對應方法,則會使用自定義方法。

self關鍵字

在C#、Java中都有一個關鍵字this用於表示當前對象,其實在ObjC中也有一個相似的關鍵字self,只是self不只能夠表示當前對象還能夠表示類自己,也就是說它既能夠用在靜態方法中又能夠用在動態方法中。

Perosn.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property NSString *name;
@property int age;

-(void)setName:(NSString *)name andAge:(int)age;

+(void)showMessage;
@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person
-(void)setName:(NSString *)name andAge:(int)age{
//    _name=name;
//    _age=age;
    self.name=name;
    self.age=age;
}

+(void)printInfo{
    NSLog(@"Hello,World!");
}

+(void)showMessage{
    [self printInfo];
}
@end

main.m

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {

    Person *p=[[Person alloc]init];
    [p setName:@"Kenshin" andAge:28];
    [Person showMessage];
    
    return 0;
}

在上面代碼中能夠看到setName: andAge:方法是一個動態方法,此時self就表明調用對象;而在showMessage方法中self調用了類的靜態方法printInfo,此時self表明調用的類;所以能夠總結出在ObjC中self就表明當前方法的調用者。

擴展

先看一段代碼

Person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property NSString *name;
@property int age;

@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

-(void)setName:(NSString *)name{
    self.name=name;
}

@end

main.m

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    
    Person *p=[[Person alloc]init];
    
    p.name=@"Kenshin";
    
    return 0;
}

若是運行上面的代碼將會發生死循環,緣由很簡單,self.name=name自己就會調用Person的setName方法,如此反覆就會形成循環操做,全部通常若是須要重寫setter方法,能夠直接寫成_name=name,由此咱們也能夠看到爲何以前即便沒有使用@property生成對應的屬性方法,在定義成員變量時也都加上了下劃線(這是一好的編碼習慣)。

構造方法

在前面的代碼中咱們已經看到若是要初始化一個類須要調用init方法,那麼下面看一下如何自定義構造方法

Person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property NSString *name;
@property int age;

-(id)initWithName:(NSString *)name andAge:(int )age;

@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

//自定義構造方法
-(id)initWithName:(NSString *)name andAge:(int)age{
    if(self=[super init]){ //super表明父類
        self.name=name;
        self.age=age;
    }
    return self;
}

@end

main.m

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    
    Person *p=[[Person alloc]initWithName:@"Kenshin" andAge:28];
    NSLog(@"name=%@,age=%i",p.name,p.age);
    //結果:name=Kenshin,age=28
    return 0;
}

在ObjC中super表明父類,經過調用父類的方法給當前對象賦值,而後判斷這個對象是否爲nil,若是不爲空則依次給name、age屬性賦值。

擴展

經過自定義構造方法當然能夠簡化代碼,可是在使用時還要手動申請內存,在ObjC中通常咱們經過定義一個靜態方法來解決這個問題

Person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property NSString *name;
@property int age;

-(id)initWithName:(NSString *)name andAge:(int )age;

+(id)personWithName:(NSString *)name andAge:(int )age;
@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

//自定義構造方法
-(id)initWithName:(NSString *)name andAge:(int)age{
    if(self=[super init]){ //super表明父類
        self.name=name;
        self.age=age;
    }
    return self;
}

//經過靜態方法得到一個對象
+(id)personWithName:(NSString *)name andAge:(int)age{
    Person *p=[[Person alloc]initWithName:name andAge:age];
    return p;
}
@end

main.m

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    
    Person *p=[[Person alloc]initWithName:@"Kenshin" andAge:28];
    NSLog(@"name=%@,age=%i",p.name,p.age);
    //結果:name=Kenshin,age=28
    
    Person *p2=[Person personWithName:@"Kaoru" andAge:27];
    NSLog(@"name=%@,age=%i",p2.name,p2.age);
    //結果:name=Kaoru,age=27
    return 0;
}

description方法

在C#中每一個類都有一個ToString()方法(java中叫作toString())用於打印一個對象的信息,在ObjC中這個方法叫description,例如在前面的Person類中咱們能夠重寫這個方法用於打印調試

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

-(NSString *)description{
    return [NSString stringWithFormat:@"{name:%@,age:%i}",self.name,self.age];
}

@end

main.m

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {

    Person *p=[[Person alloc]init];
    p.name=@"Kenshin";
    p.age=28;
    
    NSLog(@"%@",p);//此時會調用對象description方法返回對應的描述信息
    /*結果:
     name:Kenshin,age:28}
     */
    
    return 0;
}

注意上面NSLog中的格式符是%@,當使用%@輸出一個對象時,ObjC會調用個對象的description返回對應的信息進行輸出,默認狀況下若是咱們不重寫description方法,輸出內容是類名和地址,例如Person則輸出「<Person: 0x100202310>」。

須要強調的是千萬不要在description中打印輸出self,由於當輸出self時會調用該對象的description方法,如此一來就會形成死循環。

繼承

繼承是面向對象三大特徵之一,既然ObjC是面嚮對象語言,固然一樣支持繼承。事實上前面定義的Person類自己就繼承於NSObject,下面再簡單看一個例子,這裏部分假設咱們還有一個Student類繼承於Person類,並且這個類有一個分數(score)屬性。

Person.h

//
//  Person.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject{
    @protected
    NSString *_nation;
}

#pragma mark - 屬性
#pragma mark 姓名
@property (nonatomic,copy) NSString *name;
#pragma mark 年齡
@property (nonatomic,assign) int age;
#pragma mark 籍貫
@property (nonatomic,copy) NSString *nation;

#pragma mark - 動態方法
#pragma mark 帶有參數的構造函數
-(id)initWithName:(NSString *)name andAge:(int )age;

#pragma mark - 靜態方法
#pragma mark 經過靜態方法返回一個對象
+(id)personWithName:(NSString *)name andAge:(int )age;

@end

Person.m

//
//  Person.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@implementation Person

#pragma mark - 動態方法
#pragma mark 帶有參數的構造函數
-(id)initWithName:(NSString *)name andAge:(int)age{
    if(self=[super init]){ //super表明父類
        self.name=name;
        self.age=age;
    }
    return self;
}

#pragma mark - 靜態方法
#pragma mark 經過靜態方法返回一個對象
+(id)personWithName:(NSString *)name andAge:(int)age{
    Person *p=[[Person alloc]initWithName:name andAge:age];
    return p;
}

#pragma mark - 重寫方法
#pragma mark 重寫description
-(NSString *)description{
    return [NSString stringWithFormat:@"{name:%@,age:%i}",self.name,self.age];
}

@end

Student.h

//
//  Student.h
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Person.h"

@interface Student : Person

#pragma mark - 屬性
#pragma mark 分數
@property (nonatomic,assign) float score;

#pragma mark - 動態方法
#pragma mark 帶有參數的構造函數
-(id)initWithName:(NSString *)name andAge:(int )age andScore:(float)score;

#pragma mark - 靜態方法
#pragma mark 經過靜態方法返回一個對象
+(id)studentWithName:(NSString *)name andAge:(int )age andScore:(float)score;

@end

Student.m

//
//  Student.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "Student.h"

@implementation Student

#pragma mark - 動態方法
#pragma mark 帶有參數的構造函數
-(id)initWithName:(NSString *)name andAge:(int )age andScore:(float)score{
    if(self=[super initWithName:name andAge:age]){
        self.score=score;
    }
    return self;
}

#pragma mark - 靜態方法
#pragma mark 經過靜態方法返回一個對象
+(id)studentWithName:(NSString *)name andAge:(int)age andScore:(float)score{
    Student *s=[[Student alloc]initWithName:name andAge:age andScore:score];
    return s;
}

#pragma mark - 重寫方法
#pragma mark 重寫description
-(NSString *)description{
    return [NSString stringWithFormat:@"{name:%@,age:%i,nation:%@,scroe:%.2f}",self.name,self.age,self->_nation,self.score]; //注意這裏訪問了父類的屬性和方法
}

@end

main.m

//
//  main.m
//  ClassAndObject
//
//  Created by Kenshin Cui on 14-2-1.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"

int main(int argc, const char * argv[]) {
    
    Person *p=[Person personWithName:@"Kenshin" andAge:28];
    NSLog(@"p=%@",p);
    
    Student *s=[Student studentWithName:@"Kaoru" andAge:27 andScore:100];
    s.nation=@"henan";
    NSLog(@"s=%@",s);
    
    
    return 0;
}

繼承知識比較簡單,經過上面的代碼基本上就能夠了解,這裏不作詳細論述。

相關文章
相關標籤/搜索