《Objective-C》書籍閱讀筆記

來源:互聯網
上載者:User

標籤:

*   代表有地址的指標
id可以用來存放引用的指標,如:
void drawShapes(id shapes[],int count){
id shape = shapes[0];
}
[shape draw]在Objective_c中,方括還可以表示:用於通知某個對象改取做什麼.方括弧裡的第一項是對象,其餘部分是需要對象執行的操作.通知名稱為shape的對象執行draw操作.

在Objective_c中,通知某個對象執行某種操作成為發送訊息(也有人稱之為"調用方法").代碼[shape draw] 表示向shape對象發送了draw訊息.[shape draw]可以理解成"向shape發送draw訊息.

首字母大寫類名,指向對象的變數不需要首字母大寫.

訊息(message)是對象可以執行的操作,用於通知對象去做什麼,在[shape draw]的代碼中,通過想shape對象發送draw訊息來通知對象繪製自身.對象接受訊息後,將查詢相應的類,以便找到正確的代碼來運行.

方法(method)是為響應訊息而啟動並執行代碼.
方法調度,是Objective-C使用的一種機制,用於推測執行什麼方法以相應某個特定的訊息.

編寫初始化方法:
(id) init{
if(self = [super init]){
engine = [Engine new];
tires[0] = [Tire new];
tires[1] = [Tire new];
}
return (self);
}//init

點運算式的妙用
如果點運算式出現在了等號(=)的左邊,該變數名稱的setter方法(-setRainHandling:和-setSnowHandling:)將被調用.如果點運算式出現再了物件變數的右邊,則該變數名稱的getter方法(-rainHandling和 -snowHandling)將被調用
如果在訪問屬性時遇到了奇怪的錯誤資訊,提示訪問的對象不是struct類型,請檢查當前的類是否已經包含了所需的所有必備標頭檔.


--------------@interface部分

@interface Circle : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}

-(void) setFillColor:(ShapeColor) fillColor;
-(void) setBounds:(ShapeRect)bounds;

在Objective-c中只要看到@符號,就可以把它看成是對C語言的擴充.

- (void) draw;前面的短線表明這是Objective-c方法的聲明.這是區分函數原型與方法聲明的一種方式,函數原型中沒有先行短線.短線後是方法的傳回值,位於圓括弧內.

- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect)bounds;
其中的每個方法都有一個參數,setFillColor有一個顏色參數,Circle類在繪製自身時會使用該顏色.setBounds:有一個矩形地區參數,Circle類使用該地區來確定他們的邊界.

中綴符
Objective-c有一種名為中綴符(infix notation)的文法技術.方法的名稱及其參數都是合在一起的.
例如,你可以這樣調用帶一個參數的方法:
[circle setFillColor: kRedColor]
帶兩個參數的方法調用如下所示:
[textThing setStringValue:@"hello three" color:kBlueColor];

注意冒號
注意,冒號是方法名稱非常重要的組成部分.方法
- (void) scratchTheCat;
不同於
- (void) scratchTheCat: (CatType) critter;
如果方法使用參數,則需要冒號,否則不需要冒號.

最後一行代碼告訴編譯器,我們已經完成了Circle類的聲明.
@end //Circle
雖然這並不是必須的,但我們還是提倡在所有的@end語句添加註釋來註明類的名稱.這是一個好習慣.

[email protected]部分
interface部分,用於定義類的公用借口.通常,介面被稱為API.而真正使對象能夠啟動並執行代碼位於@implementation部分中.
以下是完整的Circle類實現:

@implementation Circle

-(void)setFillColor:(ShapeColor)c
{
fillColor = c;
}//setFillColor

-(void) setBounds:(ShapeRect)b
{
bounds = b;
}//setBounds
在@implementation Circle中,fillColor  和 bounds 是直接繼承了@interface聲明的變數,所以不需要再額外定義.

@implementation Circle 是一個編譯器指令,表明你將為某個類提供代碼.類名出現再@implementation之後.該行的結尾出沒有分號,因為在Objective-c編譯器指令後不必使用分號.

你也許會認為,既然單獨在@implementation指令中定義方法,就不能從該實現之外訪問該方法.但事實並非如此,Objective-c中不存在真正的私人方法,也無法把某個方法標識未私人方法,從而禁止其他代碼調用它.這是obective-c動態本質的副作用.

@interface和@implemention間的參數名不同是允許的.

設定engine屬性的存取方法:
- (Engine *) engine;
- (void) setEngine: (Engine *) newEngine;
實現代碼:
- (Engine*)engine
{
return (engine);
}

-(void) setEngine:(Engine *) newEngine
{
engine = newEngine;
}

實際使用:
Engine *engine = [Engine new]
[car setEngine: engine];
NSLog(@"the car‘s engine is %@",[car engine]);


設定tires屬性的存取方法:
tires的存取方法稍微複雜一點:
-(void) setTire:(Tire *) tire atIndex: (int) index;
-(Tire *) tireAtIndex: (int) index;

實現代碼:
-(void)setTire:(Tire *) tire atIndex: (int) inex{
if(index < 0 || index>3){
NSLog (@"bad index (%d) in setTire:atIndex:",index);
exit(1);
}
tires[index] = tire;
}

-(Tire *) tireAtIndex: (int) index
{
if(index < 0 || index >3){
NSLog(@"bad index (%d) in "tireAtIndex:",index;
exit(1);
}
return (tires[index]);
}


IOS類的代碼分為兩部分.
一部分是介面,用來展示類的構造.介面包含了使用該類所需要的所有資訊.編譯器將@interface部分編譯後,你才能使用該類的對象,調用類方法,將對象複合到其他類中,以及建立子類.
原始碼的另一個組成部分是實現.@implementation部分告訴Objectiveive-c編譯器如何讓該類工作.這部分代碼實現了介面所聲明的方法.


@interface是放在 .h 標頭檔中,  @implementation是放在.m 源檔案中.
將 CarParts-Split.m檔案中剪下Tire類的@interface部分,並粘貼到Tire.h中,檔案應如下所示

#import <Cocoa/Cocoa.h>

@interface Tire : NSObject
@end

接下來,從CarParts-Split.m中剪下Tire類的@implementation部分,並粘貼到Tire.m中,你需要在檔案首行加上語句#import "Tire.h".檔案應如下所示.

#import "Tire"
@implementation Tire
-(NSString *) description
{
return(@"I am a tire .Ilast a while);
}
@end;
檔案中的第一個import語句,並沒有像之前那樣匯入標頭檔Cocoa.h或者Foundation.h,而是匯入了該類的標頭檔.這是一個標準化的過程.在程式編譯時間,如果你碰到了注入"Cannot find interface declaration for Tire " (無法找到Tire類的介面定義)


減少依賴關係:
Objective-c引入了關鍵字@class來告訴編譯器:"這是一個類,所以我只會通過指標來引用它"
在將Car類移動到屬於其自身的檔案時會用到@class.在Xcode中,使用和移植Tire類以及engine類相同的方法來建立Car.h和Car.m,來複製Car的@interface部分並粘貼到Car.h中,如下所示:

#import <Cocoa/Cocoa.h>

@interface Car : NSObject
-(void)setEngine:(Engine*)newEngine;
-(Engine *) engine;
-(void)setTire:(Tire *)tire atIndex: (int) index;
-(Tire *) tireAtIndex:(int)index;
-(void)print;
@end//Car
如果我們現在就使用這個標頭檔,就會從編譯器那裡得到錯誤訊息,告訴我們不明白Trie和Engine是什麼.這條錯誤資訊很可能會像這樣:error:expected a type"Tire",編譯器這是在說"我無法理解這個"
有兩種方法來解決這個錯誤問題.第一種就是用@import語句匯入Tire.h和engine.h.這樣編譯器會獲得這兩個類的許多資訊.
此外還有一個更好的方法.如果仔細觀察Car類的借口,你會發現它只是通過指標引用Tire和Engine.這是@class可以完成的工作.下面是加入@class代碼的Car.h檔案內容.

#import<Cocoa/Cocoa.h>

@class Tire;
@class Engine;
@interfaceCar:NSObject
-(void)setEngine:(Engine *) newEngine;
-(Engine *)engine;
-(void)setTire:(Tire *)tireatIndex:(int)index;
-(Tire*)tireAtIndex:(int)index;
-(void)print;
@end//Car
這樣就足以告知編譯器處理Car類的@interface部分所需要的全部資訊了.
說明:@class差ungjainle一個前後引用.這是在告訴編譯器:"相信我.以後你自然會知道這個類到底是什麼,但是現在,你知道這些足以.
如果有循環相依性關係.@class也很有用.即A類使用B類,B類也使用A類.如果視圖通過#inport語句讓這兩個類互相引用,那麼就會出現編譯錯誤.但是如果在A.h檔案中使用@class B,在B.h中使用@class A,那麼這兩個類就可以互相引用了.

編譯器需要Crowdsourced Security Testing道所有關於超類的資訊才能成功地為其子類編譯@interface部分.


FoundationKit介紹
一些有用的資料類型
typedef struct _NSRange{
unsignedintlocation;
unsigned intlength;
}NSRange;
這個結構體用來表示相關事物的範圍,通常是 字串裡的字元範圍或者數組裡的元素範圍.Location欄位存放在該範圍的起始位置,而length欄位則是該範圍內所含元素的個數.在字串"Objective-C is a cool language"中,單詞cool可以用location為17,length為4的範圍來表示.location 還可以用NSNotFound這個值來表示沒有範圍,比如變數沒有初始化.
建立NSRange有三種方式,
第一種,直接給欄位賦值:
NSRangerange;
range.location = 17;
range.length = 4;
第二種 應用C語言的彙總結構賦值機制
NSRange range = {17,4};
第三種方式是Cocoa提供的一個快捷函數NSMakeRange();
NSRANGE range = NSMakeRange(17,4);
使用NSMakeRange();的好處是你可以在任何能夠使用函數的地方使用它,列如在方法的調用中,將其作為參數進行傳遞.
[anObjectiveflarbulateWithRange:NSMakeRange(13,15)];

幾何資料類型
經常看到用來處理幾何圖形的資料類型,它們的名稱都帶有CG首碼,如CGPoint 和 CGSize.這些類型是有CoreGraphics架構提供,用來進行2D渲染.CoreGraphics是有C語言所寫的.因此可以在代碼中使用C語言的資料類型.CGPoint表示的是笛卡爾平面中的一個座標.
structCGPoint
{
float x;
float y;
}
CGSize用來儲存長度和寬度;
structCGSize
{
float width;
floatheight;
}

字串:

關於大小
NSString中另一個好用的方法(執行個體方法)是length,它返回的是字串中的字元個數
-(NSString)length;
可以這樣使用它;
NSUIntegerlength=[heightlength];
也可以在運算式中使用它,如下所示.
if([height length] > 35){
NSLog(@"wow,you‘re really tall!");
}
說明:NSString的length方法能夠精確無誤的處理各種語言的字串,如含有俄文,中文或者日文字元的字串,以及使用Unicode國際字元標準的字串.

字串比較
isEqualToString:可以用來比較接收方(receiver,接收訊息的對象)和作為參數傳遞過來的字串.isEqualToString:返回一個BOOL值(YES或NO)來表示兩個字串的內容是否相同.
要比較兩個字串,可以使用compare:方法,其聲明如下.
-(NSComparisonResult)compare:(NSString *)aString;
compare:將接收對象和床底過來的字串逐個進行比較,它返回一個NSComparisonResult(也就是一個enum型枚舉)來顯示比較結果.
enum{
NSOrderAscending=-1,
NSOrderSame,
NSOrderDescending
}
typedefNSIntegerNSComparisonResult;

說明:正確比較字串,
比較兩個字串是否相等時,應該使用isEqualToString;,而不能僅僅比較字串的zhi指標值,舉個例子:
if([thing1 isEqualToString: thing2]){
NSLog (@"Thestring are the same!");
}//比較兩個字串之間的內容

不同於
if(thing1==thing2){
NSLog(@"They are the same Objective!");
}//判斷兩個字串的指標數值,而不是他們的所指對象.

因此,如果你想檢查兩個對象(thing1和thing2)是否為同一事物,就應該使用運算子==.如果是想查看是否相等(即這兩個字串是否內容相同,)那麼請使用isEqualToString.

compare:進行的是區分大小寫比較. @"Bork"和@"bork"的比較是不回返回NSOrdedSame的.如果compare:返回的結果是NSOrderedAscending,那麼左側的數值就小於右側的數值,即比較的目標在字母表中的排序文職比傳遞進來的字串更靠前.比如,[@"aardvark" compare: @"zygote"]將會返回NSOrderedAscending.

檢查字串是否以另一個字串開頭,判斷字串是否以另一個字串結尾.
-(BOOL)hasPrefix:(NSString *) aString;
-(Bool)hasSuffix:(NSString *) aString;

例:
NSString*fileName=@"draft-chapter.pages";
if([fileName hasPrefix: @"draft"]){
//thisisadraft
}
if([fileNamehasSuffix: @".mov"]){
//thisisamovie
}
如果你想知道字串的某處是否包含其他字串,請使用rangeOfString:.
-(NSRange)rangeOfString:(NSString *)aString;
將rangeOfString:發送給一個NSString對象時,傳遞的參數是要尋找的字元.它將會返回一個NSRange結構體.告訴你與這個字串相匹配的部分在哪裡以及能夠匹配上的字元個數.
例:
NSRangerange= [fileNamerangeOfString:@"chapter"];
返回的range.location為6,range.length為7.如果傳遞的參數在接收字串中沒有找到,那麼range.location則等於NSNotFound.

NSArray類有兩個限制.首先,它只能儲存Objectiveive-C對象,而不能儲存原始的C語言基礎資料類型,如int,float,enum,struct和NSArray中的隨機指標.同時,你也不能在NSArray中儲存nil(對象的零值或NULL值).有很多種方法可以避開這些限制,你馬上就會看到.
可以通過類方法arrayWithObjective:建立一個新的NSArray.發送一個以逗號分隔的對象列表,在列表結尾添加nil代表列表結束(順便提一下,這就是不能在數組中儲存nil的一個原因).
NSArray建立的是不可變數組.一旦建立了一個包含特定數量的對象的數組,它就固定下來了,既不能添加也不能刪除任何元素.當然數組中包含的對象是可以改變的.
為了彌補NSArray類的不足,便有了NSMutableArray這個可變數組類.

初始化對象:
我們應該像下面這樣嵌套調用alloc和init方法
Car *car = [[Car alloc] init];
而不是像這樣
Car *car = [Car alloc]; [car init];
這種嵌套調用技術非常重要,因為初始化方法返回的對象可能與分配的對象不同,雖然這種情況很奇怪,但是它的確會發生.

點運算式的妙用,如果你在訪問屬性時遇到了奇怪的錯誤資訊,提示訪問的對象不是struct類型,請檢查當前的類是否已經包含了所需的必備標頭檔.

@class Tire;
@class Engine;
@interface Car : NSObject
{
NSString*name;
NSMutableArray*tires;
Engine*engine;
}

-(void)setName:(NSString *) newName;
-(NSString *) name;
-(void)setEngine:(Engine *) newEngine;
-(void)setTire:(Tire*) tireatIndex:(int)index;
-(Tire *)tireAtIndex:(int)index;
-(void)print;
@end//Car

記憶體管理釋放
如果是通過alloc、copy、new方法產生的對象,是需要通過release釋放的.如果是通過其他的方式產生的對象,則不需要手動釋放,比如numberWithUnsignedInt,因為它返回的對象可能是保留計數器的值為1並且已經被設定為自動釋放了.在當前活動的自動釋放池被銷毀時,我們建立的這個NSNumber對象也會被清理.

//page = 第十五章 245

《Objective-C》書籍閱讀筆記

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.