Objective-C語法入門

    Objective-C是Mac軟件開發領域最主要的開發語言。假如咱們對面向對象的思惟已經C語言都很熟悉的話,對於咱們學習Objective-C將會很是有用。假如咱們對C語言還不熟悉的話,那咱們須要學習一下C語言。 編程

    1. 方法調用(Calling Methods):
安全

    爲了可以儘快上手,咱們先來看一些簡單的例子。Objective-C語法裏面基本的方法調用是這樣的: 編程語言

[object method];
[object methodWithInput:input];
    對象的方法能夠返回值:


output = [object methodWithOutput];
output = [object methodWithInputAndOutput:inpit];
     咱們也能夠在類裏面調用如何建立對象的方法。下面的這個例子裏面,咱們調用了NSString類的string方法


id myObject = [NSString string];
     id的類型意味着myObject這個變量能夠指向任意類型的變量。 當咱們編譯這個應用程序的時候,並不知道他實現的真實的類和方法。在這個例子裏面,很明顯這個對象的類型應該是NSString,因此咱們能夠改一下他的類型:


NSString * myString = [NSString string];
      如今myString就是一個NSString類型的變量。這個時候假如咱們試圖使用一個NSString沒有實現的方法時,編譯器就會警告咱們。一定要注意在對象類型的右邊有一個星號 全部的Objective-C對象變量都是指針類型的 id類型已經預先被定義成一個指針類型了。因此咱們不須要再加星號


    2. 嵌套消息調用(Nested Messages) 函數

    在許多編程語言裏面嵌套消息,或者嵌套函數看起來就像這樣:function1 ( function2() );function2的返回值被傳遞給function1當輸入參數。 學習

    在Objective-C裏面,嵌套消息調用就像這樣:
this

[NSString stringWithFormat:[prefs format]];
    咱們應該儘可能避免在一行代碼裏面嵌套調用超過兩個。由於這樣的話,代碼的可讀性就不太好。


    3. 多參輸入的方法(Multi-Input Methods)
atom

      多個輸入參數的方法。在Objective-C裏面,一個方法名能夠被分割成幾段。在頭文件裏面,就應該這樣子來定義一個多輸入參數的方法: spa


-(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;
      咱們這樣來調用它:


BOOL result = [myData writeToFile:@"/tmp/log.txt" atomically:NO];
    參數不必定要給它命名。在運行期系統裏面這個方法真實的名字叫writeToFile:atomically:。


    4. Accessors(Getter & Setter):
設計

    在Objective-C裏面全部的實例對象默認都是私有的。全部在大多數狀況下咱們須要用accessors去讀取或者設置變量的值。有兩個語法都支持這樣的操做,這個是傳統的老的語法: 指針

[photo setCaption:@"Day at the Beach"];
output = [photo caption];

     第二行的代碼其實並不是直接去讀對象實例的變量。事實上它調用的是名叫caption的方法。在Objective-C裏大多數狀況下咱們不須要給getters加get的前綴。不管何時咱們見到方括號,其實咱們都是向一個對象或者一個類發送了一個消息

    5. Dot Syntax

    在Objective-C 2.0裏面,新增長了一個"."操做的語法。在Mac OS X 10.5裏面就使用了Objective-C 2.0語法:

photo.caption = @"Day at the Beach";
output = photo.caption;
     咱們兩種方式均可以使用。可是在一個工程裏面最好保持風格一致,只使用某一種。"."操做只可以被使用在setters和getters裏面,而不能用在通常意思的方法上。


    6. 建立對象

    主要有兩種方式來建立一個對象。第一種辦法像這面這樣:

NSString* myString = [NSString string];
      這是一種很是習慣性的風格。在這種方式狀況下,咱們建立的是系統自動釋放(autoreleased)類型的對象。 關於自動釋放類型autoreleased,咱們之後會深刻討論一下。然而在許多狀況下,咱們須要手動的去建立對象:


NSString* myString = [[NSString alloc] init];
    這是一個嵌套的方法調用。 第一個調用的NSString本身的alloc方法。這是一個相對比較底層的調用,由於他建立了內容,以及實例化了一個對象。第二塊代碼調用了新建立對象的init方法。 這個init方法實現了比較經常使用的基本設置,好比建立實例對象的參數。在一些狀況下,咱們能夠用不通的初始化方式去賦初值:


NSNumber* value = [[NSNumber alloc] initWithFloat:1.0];
    7. 基本的內存管理


    假如咱們正在爲Mac OS X開發一個應用程序,咱們能夠選擇是否啓用垃圾回收機制。這就意味着咱們不須要去考慮內存管理,除了一個特別複雜的情形咱們須要處理一下。然而,咱們有的時候咱們的開發環境沒有垃圾回收機制,好比iPhone開發的時候就沒有垃圾回收機制。在這種狀況下,咱們就須要瞭解一些基本的內存管理方面的概念。

    假如咱們手動的經過alloc建立了一個對象,咱們須要用完這個對象後release它。咱們不須要手動的去release一個autoreleased類型的對象,假如真的這樣去作的話,咱們的應用程序將會crash。

// string1 will be released automatically
NSString* string1 = [NSString string];

// must release this when done
NSString* string2 = [[NSString alloc] init];
[string2 release];
     就這個教程而言,咱們能夠人爲autoreleased對象會在當前函數方法調用完成後被釋放。 固然了,還有不少關於內存管理的只是咱們須要學習,可是這須要咱們瞭解更多的基本概念之後才能去涉及。


    8. 設計一個類的Interface

    就Objective-C語言而言,建立一個類很是簡單。它很是典型的分紅了兩個部分。 類的接口一般保存在ClassName.h文件裏,它定義了實例的參數,以及一些公開的方法。類的實現在ClassName.m文件裏。它包含了真正運行的代碼和那些方法。它還常常定義一些私有的方法。這些私有的方法對於子類是不可見的。

    這裏有一個接口文件的大概。類名Photo,因此文件名叫Photo.h:

#import "Cocoa.h" @interface Photo:NSObject {
    NSString* caption;
    NSString* photographer;
}
@end
     首先,咱們把Cocoa.h import進來。Cocoa的應用程序的全部的基本的類大多都是這樣作的。#import宏指令會自動的避免把同一個文件包含屢次。@interface符號代表這是Photo類的聲明。冒號指定了父類。上面這個例子父類就是NSObject。在大括弧裏面,有兩個變量:caption和photographer。兩個都是NSString類型的。固然了,他們也能夠是任何別的類型包括id類型的。 最後@end結束整個聲明。


    增長方法

   讓咱們爲成員變量加一些getters:

#import "Cocoa.h"
@interface Photo : NSObject {

    NSString* caption;
    NSString* photographer;
}

- caption;
- photographer;

@end
      別忘記,Objective-C方法不須要加get前綴。一個單獨小橫杆代表它是一個實例的方法。假如是一個加號的話,那就說明它是一個類的方法。編譯器默認的方法的返回類型爲id。還有全部的方法的參數的默認類型也都是id類型的。因此上面的代碼從技術上講是對的。可是不多這麼用。咱們仍是給它加上返回類型吧:


#import "Cocoa.h"
@interface Photo : NSObject {

    NSString* caption;
    NSString* photographer;
}
- (NSString*) caption;
- (NSString*) photographer;
@end
     下面咱們再加上setters:


#import "Cocoa.h"
@interface Photo : NSObject {

   NSString* caption;
   NSString* photographer;
}
- (NSString*) caption;
- (NSString*) photographer;
- (void) setCaption: (NSString*)input;
- (void) setPhototgrapher:(NSString*)input;
@end
    類的實現    


    咱們經過實現getters來建立一個類的實現:

#import "Photo.h"
@implementation Photo
- (NSString*) caption {
   return caption;
}
- (NSString*) photographer {
   return photographer;
}
@end
    這部分的代碼由@implementation再來加上類名開始,以@end結束。 就跟類的接口定義同樣,全部的方法跟接口定義裏的同樣。 全部的對象都必要既要定義也要實現。 假如咱們之前也寫過代碼的話,Objective-C裏面的getters看上去跟別的差很少。因此咱們下面就來介紹setters,它須要一點說明。


- (void) setCaption: (NSString*)input{
   [caption autorelease];
   caption = [input retain];
}
- (void) setPhotographer: (NSString*)input{
   [photographer autorelease];
   photographer = [input retain];
}
     每一個setter處理兩個變量。第一個是當前存在對象的應用。第二個是新的輸入對象。在支持垃圾回收的開發環境裏,咱們只要直接賦新值就能夠了:


- (void) setCaption: (NSString*)input {
   caption = input;
}
    可是假如咱們不能夠用垃圾回收機制的話,咱們就須要先release舊的對象,而後retain新的對象。


   有兩種方法能夠釋放一個引用對象:release 和 autorelease。標準的release會直接刪除引用。autorelease方法會在未來的某個時候去release它。在它聲明週期結束前,它會毫無疑問的存在。在本例中,上面setPhotographer中的photographer對象,將會在函數結束的時候被釋放。 

    在setter裏面用autorelease是安全的,由於新對象跟老的對象有多是同一個對象有可能指向的是同一個對象。對於一個咱們即將retain的對象,咱們不該該當即release它。這個也許如今看起來會困惑,可是隨着咱們的學習,會愈來愈能理解它。如今咱們不須要馬上徹底理解它。

    9. 初始化

    咱們能夠建立一個初始化方法去給類的實例的成員變量賦初值:

- (id) init
{
   if ( self = [super init] )
   {
      [self setCaption:@"Default Caption"];
      [self setPhotographer:@"Default Photographer"];
   }
   return self;
}
      上面的代碼感受沒啥好解釋的,雖然第二行代碼好像看上去沒啥用。這個是一個單等於號,就是把[super init]的值賦給了self。 它基本上是在調用父類去實現它的初始化。這個if代碼段是設置默認值以前驗證初始化是否成功。

    10. 釋放資源Dealloc

    這個dealloc方法是在當一個對象但願被從內容裏面刪除的時候調用。這個咱們釋放在子類裏面引用成員變量的最好的時機:

- (void) dealloc
{
   [caption release];
   [photographer release];
   [super dealloc]; 
}
      開始兩行咱們發送了release通知給了兩個成員變量。咱們不要在這裏用autorelease。用標準的release更快一點最後一行的[super dealloc]很是重要。 咱們必需要發送消息去讓父類清除它本身。假如不這麼作的話,這個對象其實沒有被清除乾淨,存在內存泄露。 dealloc在垃圾回收機制下不會被調用到。 取而代之的是,咱們須要實現finalize方法。

    11. More on Memory Management

    Objective-C的內存管理系統基於引用記數。全部咱們須要關心的就是跟蹤咱們引用,以及在運行期內是否真的釋放了內存。

    用最簡單的術語來解釋,當咱們alloc一個對象的時候,應該在某個時候retain了它。每次咱們調用了alloc或者retain以後,咱們都必需要調用release。這就是引用記數理論。可是在實踐的時候,只有兩種狀況咱們須要建立一個對象:

        1. 成爲一個類的成員變量

       2. 只臨時的在一個函數裏面被使用

    在更多的時候,一個成員變量的setter應該僅僅autorelease舊的對象,而後retain新的對象。咱們只須要在dealloc的時候調用release就能夠了。因此真正須要作的就是管理函數內部的local的引用。惟一的原則就是:假如咱們alloc或者copy了一個對象,那麼咱們在函數結束的時候須要release或者autorelease它。假如咱們是經過別的方式建立的,就無論。這裏是管理成員對象的例子:

- (void) setTotalAmount: (NSNumber*)input
{
   [totalAmount autorelease];
   totalAmount = [input retain];
}
- (void) dealloc
{
   [totalAmount release];
   [super dealloc];
}
     這裏是本地引用的例子。咱們只須要release咱們用alloc建立的對象:

NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];
NSNumber* value2 = [NSNumber numberWithFloat:14.78];

// only release value1, not value2
[value1 release];
    12.  屬性Properties

    前面咱們寫caption和author的accessors的時候,你能夠已經注意到了代碼很是簡明,應該能夠被抽象提取出來。屬性在Objective-C裏是一個新的功能。他可讓咱們自動的生成accessors,另外還有一些別的優勢。咱們能夠把上面Photo的類轉成用屬性來實現:

#import "Cocoa.h"
@interface Photo : NSObject {
   NSString* caption;
   NSString* photographer;
}
@property (retain) NSString* caption;
@property (retain) NSString* photographer;
@end
     @property是Objective-C來聲明屬性的編譯指令。括號裏面的"retain"指明瞭setter須要retain輸入的對象。這行其餘的部分指定了屬性的類型以及名字。 下面讓咱們來看看這個類的實現:

#import "Photo.h"
@implementation Photo
@synthesize caption;
@synthesize photographer;
- (void) dealloc
{
   [caption release];
   [photographer release];
   [super dealloc];
}
@end
      @synthesize指令自動的生成了咱們的setters和getters。因此咱們只須要實現類的dealloc方法。

    13. 調用nil對象的方法(Calling Methods on Nil)

    在Objective-C裏,nil對象被設計來跟NULL空指針關聯的。他們的區別就是nil是一個對象,而NULL只是一個值。並且咱們對於nil調用方法,不會產生crash或者拋出異常。這個技術被framework經過多種不一樣的方式使用。最主要的就是咱們如今在調用方法以前根本無須去檢查這個對象是不是nil。假如咱們調了nil對象的一個有返回值的方法,那麼咱們會獲得一個nil返回值。

    咱們能夠經過nil對象讓咱們的dealloc函數實現看上去更帥一點:

- (void) dealloc
{
   self.caption = nil;
   self.photographer = nil;
   [super dealloc];
}
      之因此能夠這麼作是由於咱們給把nil對象設給了一個成員變量,setter就會retain nil對象(固然了這個時候nil對象啥事情也不會作)而後release舊的對象。這個方式來釋放對象其實更好,由於這樣作的話,成員變量連指向隨機數據的機會都沒有,而經過別的方式,出現指向隨機數據的情形機會不可避免。 注意到咱們調用的self.VAR這樣的語法,這表示咱們正在用setter,並且不會引發任何內存問題。假如咱們直接去設值的話,就會有內存溢出:

    14. Categories

    Categories是Objective-C裏面最經常使用到的功能之一。基本上category可讓咱們給已經存在的類增長方法,而不須要增長一個子類。並且不須要知道它內部具體的實現。

    若是咱們想增長某個framework自帶的類的方法,這很是有效。若是咱們想在咱們程序工程的NSString可以增長一個方法,咱們就可使用category。甚至都不須要本身實現一個NSString的子類。

    好比,咱們想在NSString裏面增長一個方法來判斷它是不是一個URL,那咱們就能夠這麼作:

#import "Cocoa.h"
@interface NSString (Utilities)
- (BOOL) isURL;
@end
     這跟類的定義很是相似。區別就是category沒有父類, 並且在括號裏面要有category的名字。名字能夠隨便取,可是習慣叫法會讓人比較明白category裏面有些什麼功能的方法。這裏是具體的實現。可是要注意,這自己並非一個判斷URL很好的實現。咱們主要是爲了總體的瞭解category的概念。

#import "NSString-Utilities.h"
@implementation NSString (Utilities)
- (BOOL) isURL
{
   if ( [self hasPrefix:@"http://"] )
   return YES;
   else
   return NO;
}
@end
     如今咱們能夠在任何的NSString類對象裏均可以調用這個方法了。下面的代碼在console裏面打印的"string1 is a URL":

NSString* string1 = @"http://www.CocoaDev.cn/";
NSString* string2 = @"Pixar";
if ( [string1 isURL] )
NSLog (@"string1 is a URL");
if ( [string2 isURL] )
NSLog (@"string2 is a URL");
      跟子類不同,category不能增長成員變量。咱們還能夠用category來重寫類原先的存在的方法,可是這須要很是很是當心。 記住,當咱們經過category來修改一個類的時候,它對應用程序裏的這個類全部對象都起做用。

後記:上面Objective-C的比較基礎的大概的講了一下。Objective-C仍是比較好上手的。沒有特別的語法須要去學習。並且一些概念在Objective-C裏面被反覆運用。

相關文章
相關標籤/搜索