首先,objective-c在c語言的基礎上新增了物件導向的特性,該語言採用「訊息結構」,而非其他語言的「函式呼叫」。「訊息結構」與「函式呼叫」的關鍵區別在於「訊息結構」執行的**由執行環境來決定,而「函式呼叫」由編譯器決定。編譯器甚至不關心接收訊息物件是何型別(接收訊息的物件問題也在執行時處理,其過程為**動態繫結**,第11條詳述)。
oc的重要工作由runtime元件完成,其物件導向特性所需的資料結構和函式都在runtime元件中。比如runtime元件中含有全部的記憶體管理方法。這個runtime元件本質上是一種與**相鏈結的動態庫。這種方式使得,只更新runtime元件就可以提公升應用程式效能。而那種工作在 編譯期完成的語言,需要重新編譯**(這個地方還是有些不理解,重新編譯怎麼了。。。)
如果想理解好oc需要理解c語言的記憶體模型(這個需要搞懂,目前還沒有與看,下次再看的時候需要搞懂!),有助於理解oc的記憶體模型以及引用計數機制的工作原理。若要理解記憶體模型需要明白,**oc中的指標用來指示物件**。
比如我們宣告乙個**變數**,令其指代乙個**物件**:
nsstring *str = @"string"; //要注意區分,str是變數,@"string"是物件 str變數指向分配在堆中的某塊記憶體
要強調的是,所有的**oc語言的物件都是分配在堆中的**(那block算什麼,我得再研究研究),不能在棧中分配oc物件。(細節問題啊,我能說面試的時候考這個了嗎。。。要不說細節決定成敗呢,唉)
![記憶體布局](
此時的記憶體布局為上圖,nsstring中的資料代表字串實際內容的位元組
分配在堆中的記憶體必須直接管理,而分配在棧上用於儲存變數的記憶體會在棧幀彈出時自動清理。**oc將堆記憶體管理**(malloc和free)**抽象為一套叫做「引用計數」**(具體見29條)**的記憶體管理架構**。另外在oc**中你也會看到不帶*的變數,它們可能會使用棧空間。這些變數儲存的不是oc物件。比如:cgrect,因為它只是乙個c結構體。與建立結構體相比,建立物件有額外的開銷,例如分配和釋放記憶體,會影響效能。如果只儲存非物件型別,用結構體就可以。
這一條的核心概念就是如題,盡量不要在標頭檔案中引入其他的標頭檔案。如果你只需要宣告乙個類,那麼你就使用一種叫做「前向宣告」的辦法,即@class。然後在.m檔案中引入其標頭檔案。這種將引入標頭檔案的時機延後的方式,可以避免增加編譯時間。同時,也解決了兩個類互相引用的問題。
但是,有的時候我們不得不在標頭檔案中引入其他的標頭檔案,例如**你寫的類繼承自某個超類,就必須引入定義那個超類的標頭檔案**。同理,**如果要宣告你寫的類遵從某個協議,那麼這個協議必須有完整定義,不能使用前向宣告,前向宣告只能告訴編譯器有某個協議,而此時,編譯器要知道該協議中定義的方法**。此時有兩種途徑,一是將該協議放在乙個單獨的檔案中,否則容易產生相互依賴,而且還增加編譯時間。二是有些協議,例如委託協議就不用單獨寫在乙個標頭檔案中。此時該協議與接受協議委託的類放在一起定義才有意義。這個時候最好能在實現檔案中宣告此類實現了該委託協議。
每次匯入標頭檔案時思考一下有沒有必要。可以用@class來取代,或者如果要實現屬性、例項變數或者遵循協議,盡量移至"class-continuation分類"中。這樣可以縮減編譯時間,降低彼此的依賴程度,即降低耦合度。依賴關係過於複雜會給維護帶來麻煩。
這個字面量語法呢就是介個「@」。它可以讓你宣告一些oc物件時更加簡單,減少了**量,更易讀。
nsstringnsstring,可以醬 nsstring *str = @"123";(這在oc1.0以前做不到喲)
nsnumber還有用於封裝基本資料型別的nsnumber,你可以醬紫操作:
nsnumber *intnum = @1;
nsnumber *floatnum = @1.1f;
nsnumber *intnum = @(3*4);
nsnumber *boolnum = @yes;
nsarraynsarray *animals = @[@"cat", @"dog"]; //此時要注意,當陣列元素中有nil會丟擲異常
nsstring *dog = animals[1];
下面考慮這樣兩種情況:
nsarray *a = [nsarray arraywithobjects:obj1, obj2, obj3, nil];
nsarray *b = [@obj1, @obj2, @obj3];
如果此時obj2為nil,那麼a中只會剩下obj1,因為arraywithobjects:方法會依次處理各個引數知道nil為止。而b會丟擲異常。所以使用字面量會使得程式更加安全,因為通常插入nil說明程式有錯誤。
nsdictionary通常用nsdictionary *dic = [nsdictionary dictiionarywithobjectsandkeys:@"matt", @"first",nil];這種先是物件再是key,覺得彆扭。不如醬紫
nsdictionary *dic = @;
nsstring *last = dic[@"first"];
很簡單,很清晰。同陣列一樣,有nil拋異常。
字面量語法的侷限性如果你想使用字面量語法,那麼必須是屬於foundation框架。如果自定義了其子類,就無法使用了。
還有就是用字面量語法建立出來的是不可變的,需要醬紫:
nsmutablearray *mutablearray = [@[@obj1, @obj2, @obj3] mutablecopy];
如果我們像這樣去定義常量
#define animation_duration 0.3
這樣沒有型別資訊,預處理過程會對所有的animation_duration做個替換。假如它定義在標頭檔案中,一旦其他類引入這個標頭檔案,也都會進行替換。所以對於常量我們可以這樣定義
static const nstimeinterval kanimationduration = 0.3;
(注意:在這裡static 和 const 要一起用,const代表不能修改,static代表該變數僅在此編譯單元(即實現檔案)可見)
這樣我們就可以知道他的常量型別,有助於編寫開發文件,更易讀,關於常量的命名方法是,若常量侷限於某編譯單元之內,要在前面加k;若常量在類之外可見,需要以類名為字首。
(注意:因為oc沒有namespace,所以最好不要把常量定義在標頭檔案。如果定義在標頭檔案最好加上類名字首)
有時候你想對外公開某個常量,比如在類**中呼叫nsnotificationcenter以通知他人。派發通知時通過字串表示通知的名稱,這個名稱可以為乙個外界可見的常值變數,要注意前面要加類名字首。
// .h extern關鍵字會告訴編譯器全域性符號表中有這個符號
extern nsstring *const eocstringconstant;
// .m 這裡const代表這個指標變數不能被修改
nsstring *const eocstringconstant = @"value";
由實現檔案生成目標檔案時,編譯器會在**資料段**為字串分配空間。
一般我們在定義狀態或者選項的時候可以用列舉。
enum eocconnectionstate ;
這種方式使得實現列舉所用的資料型別取決於編譯器
後期有了些改進,可以指明用何種「底層資料型別」儲存列舉型別的變數。這樣就可以向前宣告列舉變數了,不然因為編譯器不清楚底層資料型別大小,就不知道應分配多少空間。
enum eocconnectionstate : nsinteger;
把第乙個值設定為1,後面的值會遞增1。
在foundation框架中定義了一些輔助的巨集,用這些巨集來定義列舉型別。(推薦這種方式),這些巨集具備向後相容的能力,如果目標平台支援新標準,就用新式語法,否則用舊式語法。
列舉狀態
typedef ns_enum(nsinteger, eocconnectionstate) ;
列舉選項,可以通過或操作,進行多選
typedef ns_options(nsinteger, eocpermitteddirection) ;
如何用巨集實現的就先不打出來了。
注意如果列舉需要按或進行相互組合,一定要用options,因為c++編譯器會預設運算結果的資料型別應該是nsinteger,且不允許隱式轉換,就需要自己顯式轉換。
還有一點需要注意,就是我們在用switch列舉狀態時不要加default,因為當我們新加入一種狀態時編譯器會發出警告,提示新加入狀態未在switch分支中處理,加上default就預設處理了。
python第一章筆記 第一章 基礎
參與除法的兩個數中有乙個數為浮點數,結果也為浮點數 如 1.0 2,1 2.0,1.0 2.0 python print 1.0 2 結果 0.5 print 1 2.0 結果 0.5 print 1.0 2.0 結果 0.5 整數 整數,計算結果的小數部分被截除,只保留整數部分 不會四捨五入 如 ...
第一章 緒論
1.16 void print descending int x,int y,int z 按從大到小順序輸出三個數 print descending 1.17 status fib int k,int m,int f 求k階斐波那契序列的第m項的值f gender char schoolname 校...
第一章 概述
1.模擬量輸入,輸出,開關量 閃爍 輸入,輸出及資料通訊 2.模擬量大多為開關量 3.mcu前做為前端採集器,mcu 感測器 4.開發步驟 1 i o分析 2 mcu造型 3 評估系統及相關硬體 4 設計硬體系統 5 硬體系統模組測試 6 軟體系統設計 7 系統測試 8 進一步工作 5.交叉編譯 6...