熟悉Objective-C

了解Objective-C語言的起源

Objective-C是C語言的超集,是面向?qū)ο蟮恼Z言左权。Objetive-C是動態(tài)綁定的消息結(jié)構(gòu)蜕企,在運行時才會檢查對象類型洪灯。接受消息之后劈猿,執(zhí)行的代碼由運行期環(huán)境決定仇矾。

Objective-C是一種面向?qū)ο蟮恼Z言入热,與C++和Java之類的語言類似拍棕。不同的是,Objective-C是Smalltalk演化而來的勺良,使用的是消息結(jié)構(gòu)(messaging structure)而不是函數(shù)調(diào)用(function calling)绰播。

  • 消息結(jié)構(gòu)(Objective-C)
Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];
  • 函數(shù)調(diào)用(C++)
Object *obj = new Object;
obj->perform(parameter1,parameter2);
使用函數(shù)調(diào)用的語言

以C++為例,運行時執(zhí)行的代碼由編譯器決定尚困。如果類中函數(shù)是多態(tài)的蠢箩,編譯器就會為該類生成一個虛函數(shù)表,然后自動將虛表指針添加為成員變量,根據(jù)虛表來執(zhí)行函數(shù)谬泌。

使用消息結(jié)構(gòu)的語言

以O(shè)bjective-C為例滔韵,運行時所執(zhí)行的代碼不是編譯器決定的,而是由runtime決定的掌实,不管消息是否為多態(tài)陪蜻,總是在運行時才會去查找執(zhí)行的方法,編譯器甚至不關(guān)心消息對象是何種類型贱鼻。


Objective-C的重要工作都由"runtime component"來完成,所有的面向?qū)ο蟮奶卣骱退璧娜繑?shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)都在里面宴卖。runtime component本質(zhì)上是一種與開發(fā)者所編寫的代碼相鏈接的動態(tài)庫,將代碼和程序粘合起來邻悬。這樣的話症昏,只要更新運行期組件就可以提升程序的性能。而在"編譯器"完成的語言拘悦,要想獲得類似的性能改變齿兔,就要重新編譯代碼。

聲明一個對象時础米,保存的是一個存在棧(stack)的一個指向堆(heap)中對象的指針诉儒。

NSString *someString = @"The string";
NSString *anotherString = someString; 

可以看出,只創(chuàng)建了一個NString對象和兩個指向該對象的指針挑社,說明當(dāng)前棧幀(stack frame)里分配了兩塊內(nèi)存赵讯,每塊能容納下一個指針(32位機上是4個字節(jié),64位上是8個字節(jié))蘑斧,每塊中存儲的都是NSString的真實地址靖秩。
分配在棧中用于保存對象的內(nèi)存會在棧幀被彈出時自動清理,而分配在堆中的內(nèi)存必須直接管理竖瘾。
Objective-C將堆的內(nèi)存管理抽象出來了沟突,不需要malloc和free來分配或者釋放對象所占的內(nèi),而是使用引用計數(shù)來管理捕传。
在Objective-C中惠拭,有時會噴到定義不含*的變量,這些是直接使用"椨孤郏空間"來保存的變量职辅,不是對象,比如CoreGraphies框架中的CGRect

CGRect frame;
frame.size.width = 100.0f;

CGRect是結(jié)構(gòu)體聂示,只保存基本類型的變量域携,那么如果使用Objective-C對象來做的話,每次還需要分配和釋放堆內(nèi)存鱼喉,會造成額外的開銷秀鞭,因此如果只保存int,float等"非對象類型",使用結(jié)構(gòu)體就

struct CGRect{
    CGPoint origin;
    CGSize size;
};

在類的頭文件中盡量不要引入其他頭文件

除非確有必要趋观,不要引入頭文件。盡量使用向前聲明來提及別的類气筋,然后在實現(xiàn)文件中引入那些類的頭文件拆内。這樣做可以減低類之間的耦合。

協(xié)議單獨成類宠默,并盡量將協(xié)議寫在類擴展中麸恍,而不是公共頭文件中。

在一個類A中搀矫,如果要使用類B抹沪,在類A的頭文件中應(yīng)該盡量使用向前聲明來告知編譯器需要引用這類。因為編譯這個文件的時候瓤球,并不需要知道引入的文件的所有細(xì)節(jié)融欧。在類A的實現(xiàn)文件中,在來引入類B卦羡。
也就是說噪馏,如果要在類A中使用類B,那么在頭文件A.h中只需要
@class B;
在類A的實現(xiàn)文件A.m中绿饵,若要使用B欠肾,必須知道B的所有借口細(xì)節(jié),所以
#import B.h
將引入頭文件的時機盡量延后拟赊,只有在確有需要的時候引入刺桃,這樣可以

  • 減少類使用者引入的頭文件的數(shù)量,減少編譯的時間吸祟。
  • 解決兩個類互相引用的問題

假設(shè)有個Employer類和Employee類瑟慈,它們互為各自的成員變量,那么要編譯Employer則必須知道Employee屋匕,反之亦然葛碧。如果在各自頭文件中引入對方的文件,則會導(dǎo)致"循環(huán)引用"过吻。當(dāng)解析其中一個頭文件的時候进泼,會引入另一個頭文件,而另一個頭文件又要解析之前的頭文件疮装。使用#import而不是#include雖然不會導(dǎo)致死循環(huán),但是卻會導(dǎo)致其中一個類無法被正常編譯粘都。

但是有時候也必須在頭文件中引入其他頭文件

  • 如果你的類繼承自某個超類廓推,則必須引入超類頭文件
  • 如果要聲明你寫的類遵從某個協(xié)議(protocol),則該協(xié)議也必須引入

繼承自Shape并實現(xiàn)Drawable協(xié)議的Rectangle類的頭文件

//Ractangle.h
#import "Shape.h"
#import "Drawable.h"

@interface Rectangle:Shape<Drawable>
...
@end

需要注意的是,協(xié)議最好單獨成類翩隧,不要和其他類混在一起樊展,例如在類C的文件中,聲明了協(xié)議a,當(dāng)類D要使用協(xié)議a時专缠,就要引入類C,則又編譯時間增加雷酪,且有可能造成相互引用,所以協(xié)議最好單獨成類涝婉。
還有一種協(xié)議哥力,也就是"委托協(xié)議(delegate protocol)",就可以不用單獨寫一個頭文件墩弯,因為委托協(xié)議只有與被委托的類在一起才有意義吩跋,可以將兩者寫在一起。委托協(xié)議可以寫在類擴展(class-continuation)中渔工,不需要在公共頭文件中導(dǎo)入锌钮。

具體來說,每次引入其他文件時引矩,可以如下操作

  1. 如果可以用向前聲明梁丘,就使用向前聲明
  2. 協(xié)議單獨成類
  3. 協(xié)議最好寫在類擴展中

多用字面量語法,少用與之等價的方法

應(yīng)該使用字面量語法來創(chuàng)建字符串旺韭,數(shù)值氛谜,數(shù)組,字典茂翔。與創(chuàng)建此類的常規(guī)方法相比混蔼,這么做更加簡明扼要
應(yīng)該通過取下標(biāo)操作來訪問數(shù)組下標(biāo)或者是字典中的鍵所對應(yīng)的元素
用字面量語法來創(chuàng)建數(shù)組或者字典的時候,若值中有nil珊燎,或拋出異常惭嚣,因此要確保值中不含nil

字面數(shù)值

有時候需要將整數(shù),浮點數(shù)悔政,布爾值等基本類型封裝成類的時候晚吞,可以使用NSNumber。

  • 常規(guī)方式
NSNumber *someNumber = [NSNumber numberWithInt:1];
  • 字面量語法
NSNumber *someNumber = @1;

不僅語法更加精簡谋国,而且能以NSNumber實例表示的所有數(shù)據(jù)類型都可以使用該語法

NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5f;
NSNumber *doubleNumber = @3.141592;
NSNumber *boolNumber = @YES;
NSNumber *charNumber = @'a';
字面量數(shù)組
  • 常規(guī):數(shù)組結(jié)尾處要加上nil
NSArray *animals = [NSArray arrayWithObject:@"cat",@"dog",@"mouse",@"badger",nil];
  • 字面量:數(shù)組結(jié)尾處不需要加上nil
NSArray *animal = @[@"cat",@"dog",@"mouse",@"badger"];

不僅更加簡單槽地,而且還可以使用下標(biāo)來操作
字面量語法,實際上是一種語法糖

字典字面量
  • 常規(guī)
NSDictionary *personData = [NSDictionaryWithObjectsAndKeys:
                                                   @"Matt",@"fistName",
                                                   @"Galloway",@"lastName",
                                                   [NSNumber numberWithInt:28],@"age",
                                                   nil];
  • 字面量寫法
NSDictionary *personData = 
                               @{@"fisrtName":@"Matt",
                                   @"lastName":@"Galloway"
                                   @"age":@28};

這樣寫更簡潔芦瘾,而且鍵出現(xiàn)在對象之前捌蚊,更易讀。

可變數(shù)組與字典

通過取下標(biāo)操作可以直接訪問某個下標(biāo)或者字典的對象近弟,如果容器是可變的缅糟,還可以直接修改

  • 常規(guī)做法
[mutableArray replaceObjectAtIndex:1 withObject:@"dog"];
[mutableDictionary setObject:@"Galloway" forKey:@"lastName"];
  • 字面量
mutableArray[1] = @"dog";
mutableDictionary[@"lastName"]= @"Galloway";

多用類型常量,少用#define預(yù)處理命令

不要用預(yù)處理指令定義常量
在實現(xiàn)文件中使用"static const"來定義只在編譯單元內(nèi)可見的常量
在頭文件中使用extern來聲明全局常量

假如你現(xiàn)在需要設(shè)置某個動畫時間祷愉,也許會這樣做

#define ANIMATION_DURATION 0.3

這樣定義出的來的常量

  • 沒有類型信息窗宦,看不出具體是指什么
  • 在所有引入了這個頭文件的類中赦颇,ANIMATION_DURATION都將被替換成0.3

解決方法:可以是使用類型常量

static const NSTimeInterval kAnimationDuration = 0.3;

該方式定義包括了常量類型,能清晰描述常量的意義
這里kAnimationDuration是一個類變量赴涵,這個定義可以寫在類的實現(xiàn)文件的#import和實現(xiàn)函數(shù)之間

//AnimatedView.m
#import "Animated.h"

static const NSTimeInterval kAnimationDuration = 0.3;
@implement AnimatedView
...
@end
  • 使用const,表示常量媒怯,如果在實現(xiàn)文件中企圖修改,會不成功
  • 使用static意味著該變量僅在定義此變量編譯單元可見髓窜。如果不加static扇苞,編譯器會為它創(chuàng)建一個"外部符號",如果其他編譯單元中出現(xiàn)了同名變量,則拋出錯誤信息纱烘。

事實上杨拐,同時聲明為static和const之后,效果相當(dāng)于在該編譯單元進行了宏替換擂啥。

有時候哄陶,需要公開某個常量,比方說哺壶,你可能使用NSNotificationCenter來通知別人屋吨。這個變量可以聲明為外界可見的常值變量。
此類常量放需放在"全局符號表"中山宾,以便定義該常量編譯單元之外的單元使用至扰,定義方式如下

//在頭文件中
extern NSString *const StringConstant;
//在實現(xiàn)文件中
NSString *const StringConstant = @"value";

這個常量需要在頭文件中聲明,在實現(xiàn)文件中定義资锰。定義在頭文件中是為了告訴編譯器敢课,這邊有一個全局變量,請注冊到全局變量表中绷杜,而編譯器并不關(guān)心變量的定義直秆。
此變量必須定義,并且只能定義一次

用枚舉來表示狀態(tài)鞭盟、選項圾结、狀態(tài)碼

應(yīng)該用枚舉來表示狀態(tài)機的狀態(tài)
如果狀態(tài)是可以多選的,可以使用2的冪來表示枚舉齿诉,以便使用邏輯操作
使用NS_ENUM和NS_OPTIONS來代替enum

枚舉是一種常量命名的方式筝野,以套接字連接狀態(tài)為例

enum ConnectionState
{
    DisConnected,
    Connecting,
    Connected,};
typedof enum ConnetionState ConnectionState;   //這樣下次用枚舉的時候就不用加enum

枚舉默認(rèn)是使用NSInteger從0開始標(biāo)識,也可以自行改變標(biāo)識方式

enum ConnectionState
{
    DisConnected=1, //從1開始
    Connecting,        //2
    Connected,         //3};
typedof enum ConnetionState ConnectionState;   //這樣下次用枚舉的時候就不用加enum

當(dāng)定義選項的時候粤剧,如果可以彼此組合歇竟,只要枚舉得當(dāng),就可以通過"按位或操作符"來組合
如果iOS UI框架中有如下枚舉

enum UIViewAutoresizing{
    UIVIewAutosizingNone                                  = 0,
    UIViewAutosizingFlexibleLeftMargin              = 1 <<0,
    UIViewAutosizingFlexibleWidth                      = 1 <<1,
    UIViewAutosizingFlexibleRightMargin            = 1 <<2,
    UIViewAutosizingFlexibleTopMargin              = 1 <<3,
    UIViewAutosizingFlexibleHeight                     = 1 <<4,
    UIViewAutosizingFlexibleBottomMargin         = 1<<5,
}

每個選項都可以啟用或禁用


Foundation框架定義了一些輔助宏抵恋,日常中要避免使用C風(fēng)格的enum盡量使用NS_ENUM和NS_OPTION
用法如下

typedef NS_ENUM(NSUInteger,ConnectionState)
{
    Disconnected,
    Connecting,
    Connected,};
typedef NS_OPTION(NSUInteger,PermiitedDirection)
{
    Up                =1<<0,
    Down           =1<<1,
    Left              =1<<2,
    Right            =1<<3,};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焕议,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子馋记,更是在濱河造成了極大的恐慌号坡,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梯醒,死亡現(xiàn)場離奇詭異宽堆,居然都是意外死亡,警方通過查閱死者的電腦和手機茸习,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門畜隶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人号胚,你說我怎么就攤上這事籽慢。” “怎么了猫胁?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵箱亿,是天一觀的道長。 經(jīng)常有香客問我弃秆,道長届惋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任菠赚,我火速辦了婚禮脑豹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘衡查。我一直安慰自己瘩欺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布拌牲。 她就那樣靜靜地躺著俱饿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪们拙。 梳的紋絲不亂的頭發(fā)上稍途,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音砚婆,去河邊找鬼械拍。 笑死,一個胖子當(dāng)著我的面吹牛装盯,可吹牛的內(nèi)容都是我干的坷虑。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼埂奈,長吁一口氣:“原來是場噩夢啊……” “哼迄损!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起账磺,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤芹敌,失蹤者是張志新(化名)和其女友劉穎痊远,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氏捞,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡碧聪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了液茎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逞姿。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖捆等,靈堂內(nèi)的尸體忽然破棺而出滞造,到底是詐尸還是另有隱情,我是刑警寧澤栋烤,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布谒养,位于F島的核電站,受9級特大地震影響明郭,放射性物質(zhì)發(fā)生泄漏蝴光。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一达址、第九天 我趴在偏房一處隱蔽的房頂上張望蔑祟。 院中可真熱鬧,春花似錦沉唠、人聲如沸疆虚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽径簿。三九已至,卻和暖如春嘀韧,著一層夾襖步出監(jiān)牢的瞬間篇亭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工锄贷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留译蒂,地道東北人。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓谊却,卻偏偏與公主長得像柔昼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子炎辨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,576評論 2 349

推薦閱讀更多精彩內(nèi)容