Objective-C基础语法高速入门
方法調用(Calling Methods)
為了可以盡快上手。我們先來看一些簡單的樣例。
Objective-C語法里面主要的方法調用是這種:
[object method]; ?
?
[object methodWithInput:input]; ?
?
對象的方法能夠返回值:
output = [object methodWithOutput]; ?
?
output = [object methodWithInputAndOutput:input]; ?
?
我們也能夠在類里面調用怎樣創建對象的方法。以下的這個樣例里面,我們調用了NSString類的string方法:
id myObject = [NSString string]; ?
?
id的類型意味著myObject這個變量能夠指向隨意類型的變量。
當我們編譯這個應用程序的時候,并不知道他實現的真實的類和方法。
在這個樣例里面,非常明顯這個對象的類型應該是NSString。所以我們能夠改一下他的類型:
NSString* myString = [NSString string]; ?
?
如今myString就是一個NSString類型的變量。這個時候假如我們試圖使用一個NSString沒有實現的方法時,編譯器就會警告我們。
一定要注意在對象類型的右邊有一個星號。
全部的Objective-C對象變量都是指針類型的。
id類型已經預先被定義成一個指針類型了。
所以我們不須要再加星號。
嵌套消息調用(Nested Messages)
在很多編程語言里面嵌套消息。或者嵌套函數看起來就像這樣:
function1 ( function2() ); ?
function2的返回值被傳遞給function1當輸入參數。在Objective-C里面。嵌套消息調用就像這樣:
[NSString stringWithFormat:[prefs format]]; ?
我們應該盡量避免在一行代碼里面嵌套調用超過兩個。
由于這種話,代碼的可讀性就不太好。
多參輸入的方法(Multi-Input Methods)
多個輸入參數的方法。
在Objective-C里面,一個方法名能夠被切割成幾段。
在頭文件中面,就應該這樣子來定義一個多輸入參數的方法:
-(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile; ?
?
我們這樣來調用它:
BOOL result = [myData writeToFile:@"/tmp/log.txt" atomically:NO]; ?
?
參數不一定要給它命名。在執行期系統里面這種方法真實的名字叫writeToFile:atomically:。
Accessors(Getter & Setter) ?
?
在Objective-C里面全部的實例對象默認都是私有的。
全部在大多數情況下我們須要用accessors去讀取或者設置變量的值。
有兩個語法都支持這種操作,這個時傳統的老的語法:
[photo setCaption:@"Day at the Beach"]; ?
output = [photo caption]; ?
?
第二行的代碼其實并不是直接去讀對象實例的變量。
其實它調用的是名叫caption的方法。
在Objective-C里大多數情況下我們不須要給getters加get的前綴。
不管什么時候我們見到方括號,事實上我們都是向一個對象或者一個類發送了一個消息。
Dot Syntax
在Objective-C 2.0里面。新添加了一個"."操作的語法。在Mac OS X 10.5里面就使用了Objective-C 2.0語法:
photo.caption = @"Day at the Beach"; ?
output = photo.caption; ?
?
我們兩種方式都可以使用。可是在一個project里面最好保持風格一致。僅僅使用某一種。
"."操作僅僅可以被使用在setters和getters里面,而不能用在一般意思的方法上。
創建對象
主要有兩種方式來創建一個對象。
第一種辦法像這面這樣:
NSString* myString = [NSString string]; ?
?
這是一種很習慣性的風格。在這樣的方式情況下。我們創建的是系統自己主動釋放(autoreleased)類型的對象。
關于自己主動釋放類型autoreleased,我們以后會深入討論一下。然而在很多情況下,我們須要手動的去創建對象:
NSString* myString = [[NSString alloc] init]; ?
?
這是一個嵌套的方法調用。第一個調用的NSString自己的alloc方法。這是一個相對照較底層的調用,由于他創建了內容,以及實例化了一個對象。
第二塊代碼調用了新創建對象的init方法。這個init方法實現了比較經常使用的基本設置,比方創建實例對象的參數。對于一般開發者而言,實現這個客戶的類的詳細的細節并不清楚。
在一些情況下,我們能夠用不通的初始化方式去賦初值:
NSNumber* value = [[NSNumber alloc] initWithFloat:1.0]; ?
?
主要的內存管理
假如我們正在為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對象會在當前函數方法調用完畢后被釋放。
當然了,還有非常多關于內存管理的僅僅是我們須要學習。可是這須要我們了解很多其它的基本概念以后才干去涉及。
設計一個類的Interface
就Objective-C語言而言。創建一個類很easy。它很典型的分成了兩個部分。
類的接口通常保存在ClassName.h文件中,它定義了實例的參數。以及一些公開的方法。
類的實如今ClassName.m文件中。它包括了真正執行的代碼和那些方法。它還常常定義一些私有的方法。這些私有的方法對于子類是不可見的。
這里有一個接口文件的大概。類名Photo,所以文件名稱叫Photo.h:
#import ?
?
@interface Photo : NSObject { ?
?
NSString* caption; ?
?
NSString* photographer; ?
?
} ?
?
@end ?
?
首先,我們把Cocoa.h import進來。Cocoa的應用程序的全部的主要的類大多都是這樣做的。#import宏指令會自己主動的避免把同一個文件包括多次。
@interface符號表明這是Photo類的聲明。冒號指定了父類。
上面這個樣例父類就是NSObject。
在大括弧里面,有兩個變量:caption和photographer。兩個都是NSString類型的。
當然了,他們也能夠是不論什么別的類型包含id類型的。
最后@end結束整個聲明。
添加方法
讓我們為成員變量加一些getters:
#import ?
?
@interface Photo : NSObject { ?
?
NSString* caption; ?
?
NSString* photographer; ?
?
} ?
?
- caption; ?
?
- photographer; ?
?
@end ?
?
別忘記,Objective-C方法不須要加get前綴。一個單獨小橫桿表明它是一個實例的方法。假如是一個加號的話,那就說明它是一個類的方法。
編譯器默認的方法的返回類型為id。還有全部的方法的參數的默認類型也都是id類型的。所以上面的代碼從技術上講是對的。可是非常少這么用。我們還是給它加上返回類型吧:
#import ?
?
@interface Photo : NSObject { ?
?
NSString* caption; ?
?
NSString* photographer; ?
?
} ?
?
- (NSString*) caption; ?
?
- (NSString*) photographer; ?
?
@end ?
?
以下我們再加上setters:
#import ?
?
@interface Photo : NSObject { ?
?
NSString* caption; ?
?
NSString* photographer; ?
?
} ?
?
- (NSString*) caption; ?
?
- (NSString*) photographer; ?
?
- (void) setCaption: (NSString*)input; ?
?
- (void) setPhotographer: (NSString*)input; ?
?
@end ?
?
Setters不須要返回不論什么值。所以我們把它的類型指定為void.
類的實現
我們通過實現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; ?
?
} ?
?
可是假如我們不能夠用垃圾回收機制的話,我們就須要先retain舊的對象,然后retain新的對象。
有兩種方法能夠釋放一個引用對象:release 和 autorelease。標準的release會直接刪除引用。autorelease方法會在將來的某個時候去release它。
在它聲明周期結束前。它會毫無疑問的存在。在本例中,上面setPhotographer中的photographer對象。將會在函數結束的時候被釋放。
在setter里面用autorelease是安全的,由于新對象跟老的對象有可能是同一個對象有可能指向的是同一個對象。對于一個我們即將retain的對象。我們不應該馬上release它。
這個或許如今看起來會困惑,可是隨著我們的學習。會越來越能理解它。如今我們不須要立馬全然理解它。
初始化
我們能夠創建一個初始化方法去給類的實例的成員變量賦初值:
- (id) init ?
?
{ ?
?
if ( self = [super init] ) ?
?
{ ?
?
[self setCaption:@"Default Caption"]; ?
?
[self setPhotographer:@"Default Photographer"]; ?
?
} ?
?
return self; ?
?
} ?
?
上面的代碼感覺沒啥好解釋的,盡管第二行代碼好像看上去沒啥用。
這個是一個單等于號,就是把[super init]的值賦給了self。
它基本上是在調用父類去實現它的初始化。這個if代碼段是設置默認值之前驗證初始化是否成功。
釋放資源Dealloc
這個dealloc方法是在當一個對象希望被從內容里面刪除的時候調用。
這個我們釋放在子類里面引用成員變量的最好的時機:
- (void) dealloc ?
?
{ ?
?
[caption release]; ?
?
[photographer release]; ?
?
[super dealloc]; ?
?
} ?
?
開始兩行我們發送了release通知給了兩個成員變量。
我們不要在這里用autorelease。
用標準的release更快一點。
最后一行的[super dealloc];很重要。
我們必需要發送消息去讓父類清除它自己。
假如不這么做的話,這個對象事實上沒有被清除干凈,存在內存泄露。
dealloc在垃圾回收機制下不會被調用到。
取而代之的是,我們須要實現finalize方法。
很多其它關于內存管理
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]; ?
?
這里是用本地引用對象去設一個成員變量的樣例:
NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75]; ?
?
[self setTotal:value1]; ?
?
NSNumber* value2 = [NSNumber numberWithFloat:14.78]; ?
?
[self setTotal:value2]; ?
?
[value1 release]; ?
?
注意到怎樣管理本地引用事實上都是一樣的。無論你是否把它設給了一個成員變量。
我們無須考慮setters的內部實現。
假設我們非常好的理解了這些的話,我們基本上理解了80%的Objective-C內存管理方面的內容了。
屬性Properties
前面我們寫caption和author的accessors的時候。你能夠已經注意到了代碼很簡明,應該能夠被抽象提取出來。
屬性在Objective-C里是一個新的功能。他能夠讓我們自己主動的生成accessors,另外另一些別的長處。我們能夠把上面Photo的類轉成用屬性來實現:
上面那個類原先的實現是這樣:
#import ?
?
@interface Photo : NSObject { ?
?
NSString* caption; ?
?
NSString* photographer; ?
?
} ?
?
- (NSString*) caption; ?
?
- (NSString*) photographer; ?
?
- (void) setCaption: (NSString*)input; ?
?
- (void) setPhotographer: (NSString*)input; ?
?
@end ?
?
假如用屬性來實現就是這樣:
#import ?
?
@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方法。
Accessors僅僅有當他們原先沒有的時候,才會被生成。所以能夠放心大膽的去用@synthesize來指定屬性。并且能夠任意實現你自己的getter和setter。編譯器會自己去找哪個方法沒有。
屬性聲明還有別的選項。可是限于篇幅層次,我們下次再介紹。
Logging
在Objective-C里。往console寫日記很easy。其實NSLog()跟C語言的printf()兩個函數差點兒全然同樣。除了NSLog是用額外的“%@”去獲得對象。
NSLog ( @"The current date and time is: %@", [NSDate date] ); ?
?
我們能夠log一個對象到console里去。NSLog函數調用要輸出對象的description方法。然后打印返回的NSString。我們能夠在自己的類里重寫description方法。這樣我們就能夠得到一個自己定義的字符串。
調用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,并且不會引起不論什么內存問題。
假如我們直接去設值的話,就會有內存溢出:
// incorrect. causes a memory leak. ?
// use self.caption to go through setter ?
caption = nil; ?
?
Categories
Categories是Objective-C里面最經常使用到的功能之中的一個。 基本上category能夠讓我們給已經存在的類添加方法,而不須要添加一個子類。并且不須要知道它內部詳細的實現。
假設我們想添加某個framework自帶的類的方法,這很有效。假設我們想在我們程序project的NSString可以添加一個方法,我們就行使用category。甚至都不須要自己實現一個NSString的子類。
比方,我們想在NSString里面添加一個方法來推斷它是否是一個URL。那我們就能夠這么做:
#import ?
?
@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里面被重復運用。
轉載于:https://www.cnblogs.com/zsychanpin/p/7128343.html
總結
以上是生活随笔為你收集整理的Objective-C基础语法高速入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux系统怎样查看文件夹下有多少文件
- 下一篇: jquery改变字符串中部分字符的颜色