iOS學(xué)習(xí)之 Objective - C 基礎(chǔ)知識(shí)點(diǎn)

Objective-C

1. import的用法


  • 拷貝文件內(nèi)容
    可以自動(dòng)防止文件的內(nèi)容被重復(fù)拷貝(#define宏定義)
  • Foundation 框架頭文件的路徑
    Xcode.app 顯示包內(nèi)容
    Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/Foundation.framework
  • 命令行指令
  • 編寫 Oc 源文件: .m .c
  • 編譯: cc -c xxx.m xxx.c
  • 鏈接: cc xxx.o xxx.o -framework Foundation(用到的時(shí)候才加)
  • 運(yùn)行: ./a.out
  • 主頭文件
    主頭文件:最主要的頭文件蜒茄,名字一般跟框架名稱一樣,包含了框架中的所有其他頭文件
  • Foundation框架的主頭文件名稱就是Foundation.h
    只需要包含F(xiàn)oundation框架主頭文件士修,就可以使用整個(gè)框架的東西

2. 對(duì)象方法和類方法


  • 對(duì)象方法: - 開(kāi)頭
    • 只能由對(duì)象調(diào)用
    • 對(duì)象方法中能訪問(wèn)當(dāng)前對(duì)象的成員變量(實(shí)例變量)
  • 類方法: + 開(kāi)頭
    • 只能由類名來(lái)調(diào)用
    • 類方法中不能訪問(wèn)成員變量
    • 類方法的優(yōu)點(diǎn)和使用場(chǎng)合:
    1. 不依賴于對(duì)象,執(zhí)行效率高
    2. 能用類方法,盡量用類方法
    3. 場(chǎng)合:當(dāng)方法內(nèi)部不需要使用到成員變量時(shí),就用類方法
    4. 可以允許類方法和對(duì)象方法同名

3. 成員變量和局部變量


  • 成員變量:

    • 寫在類聲明的大括號(hào)中的變量, 我們稱之為 成員變量(屬性, 實(shí)例變量)成員變量只能通過(guò)對(duì)象來(lái)訪問(wèn)
    • 注意: 成員變量不能離開(kāi)類,倔矾,離開(kāi)類之后就不是成員變量掸驱,成員變量不能在定義的同時(shí)進(jìn)行初始化
    • 存儲(chǔ): 堆(當(dāng)前對(duì)象對(duì)應(yīng)的堆的存儲(chǔ)空間中)
    • 存儲(chǔ)在堆中的數(shù)據(jù), 不會(huì)被自動(dòng)釋放, 只能程序員手動(dòng)釋放
  • 局部變量:

  • 寫在函數(shù)或者代碼塊中的變量, 我們稱之為局部變量

    • 作用域: 從定義的那一行開(kāi)始, 一直到遇到大括號(hào)或者return
    • 局部變量可以先定義再初始化, 也可以定義的同時(shí)初始化
    • 存儲(chǔ) : 棧
    • 存儲(chǔ)在棧中的數(shù)據(jù)有一個(gè)特點(diǎn), 系統(tǒng)會(huì)自動(dòng)給我們釋放
  • 全局變量

    • 寫在函數(shù)和大括號(hào)外部的變量, 我們稱之為全局變量
    • 作用域: 從定義的那一行開(kāi)始, 一直到文件末尾
    • 局部變量可以先定義在初始化, 也可以定義的同時(shí)初始化
    • 存儲(chǔ): 靜態(tài)區(qū)
    • 程序一啟動(dòng)就會(huì)分配存儲(chǔ)空間, 直到程序結(jié)束才會(huì)釋放

4. 方法和函數(shù)


  • 方法
  • 函數(shù)屬于整個(gè)文件,, 方法屬于某一個(gè)類,方法如果離開(kāi)類就不行
  • 函數(shù)可以直接調(diào)用, 方法必須用對(duì)象或者類來(lái)調(diào)用
  • 函數(shù)
  • 能寫在文件中的任意位置(@interface和@end之間除外)株茶,函數(shù)歸文件所有
  • 函數(shù)調(diào)用不依賴于對(duì)象
  • 函數(shù)內(nèi)部不能直接通過(guò)成員變量名訪問(wèn)某個(gè)對(duì)象的成員變量

5. setter 和 getter 用法簡(jiǎn)介


  • setter
  • 作用: 給成員變量賦值
  • 格式:
    1. 必須是對(duì)象方法
    2. 一定沒(méi)有返回值
    3. 方法名稱一定以set開(kāi)頭, set后面跟上成員變量的名稱, 并去掉下劃線, 然后將首字母大寫
    4. 一定有參數(shù), 并且參數(shù)類型和成員變量的類型一致, 參數(shù)名稱就是成員變量的名稱去掉下劃線
  • getter
  • 作用: 返回成員變量的值
  • 格式:
    1. 必須是對(duì)象方法
    2. 一定有返回值, 返回值類型和成員變量的類型一致
    3. 方法名稱就是成員變量的名稱去掉下劃線
    4. 一定沒(méi)有參數(shù)
  • readLoad 和 readWrite
  • 一個(gè)屬性可以只有g(shù)etter方法, 沒(méi)有setter方法, 這種屬性我們稱之為只讀屬性
  • 一個(gè)屬性也可以只有setter方法, 沒(méi)有g(shù)etter方法, 這種屬性我們稱之為只寫屬性
  • 如果既有setter方法又有g(shù)etter方法, 那么這種屬性我們稱之為可讀可寫的屬性
  • 一個(gè)屬性也可以沒(méi)有g(shù)etter和setter, 這種屬性我們稱之為私有屬性

6. self 的基本使用


  • 用法
  • 那個(gè)調(diào)用了當(dāng)前方法,self就代表誰(shuí)
  • self出現(xiàn)在對(duì)象方法中, self就代表對(duì)象
  • self出現(xiàn)在類方法中, self就代表類
  • 在對(duì)象方法利用 "self->成員變量名” 訪問(wèn)當(dāng)前對(duì)象內(nèi)部的成員變量(實(shí)例變量)
  • [self 方法名] 可以調(diào)用其他對(duì)象方法\類方法
  • self會(huì)自動(dòng)區(qū)分類方法和對(duì)象方法, 如果在類方法中使用self調(diào)用對(duì)象方法, 那么會(huì)直接報(bào)錯(cuò)
  • 不能在對(duì)象方法或者類方法中利用self調(diào)用當(dāng)前self所在的方法
  • 動(dòng)態(tài)綁定:
    動(dòng)態(tài)類型能使程序直到執(zhí)行時(shí)才確定對(duì)象的真實(shí)類型
    動(dòng)態(tài)類型綁定能使程序直到執(zhí)行時(shí)才確定要對(duì)那個(gè)對(duì)象調(diào)用的方法
  • 使用self調(diào)用本方法恕洲,導(dǎo)致死循環(huán)調(diào)用
  • #pragma mark
  • 將代碼分隔開(kāi)塔橡,方便我們進(jìn)行查找。

7. super 基本使用


  • 編譯器指令符號(hào).
  • 利用super給父類的方法發(fā)送一個(gè)消息, 那么系統(tǒng)就會(huì)自動(dòng)調(diào)用父類的方法
  • 如果以后想在子類中調(diào)用父類的方法可以使用super
  • 如果想在給父類方法進(jìn)行擴(kuò)展的同時(shí)保留父類的方法, 那么可以使用super調(diào)用父類同名的方法
  • super 在什么方法中就調(diào)用父類的什么方法

8. 面向?qū)ο蠡舅枷?/h2>

封裝

  • 原理:屏蔽內(nèi)部實(shí)現(xiàn)的細(xì)節(jié)霜第,僅僅對(duì)外提供共有的方法/接口
  • 好處:保證數(shù)據(jù)的安全性
  • 規(guī)范:一般情況下不會(huì)對(duì)外直接暴露成員變量, 都會(huì)提供一些共有的方法進(jìn)行賦值成員變量都需要封裝起來(lái)

繼承

  • 父類必須聲明在子類的前面
  • 不允許子類和父類擁有相同名稱的成員變量, 因?yàn)樽宇惱^承父類谱邪,子類將會(huì)擁有父類的所有成員變量,若在子類中定義父類同名成員變量 屬于重復(fù)定義庶诡。
  • 調(diào)用某個(gè)對(duì)象的方法時(shí), 優(yōu)先去當(dāng)前類中找, 如果么有, 去父類中找
  • 基類的私有屬性能被繼承, 不能在子類中訪問(wèn)惦银。
  • OC中的繼承是單繼承:也就是說(shuō)一個(gè)類只能一個(gè)父類, 不能繼承多個(gè)父類
  • 缺點(diǎn):耦合性太強(qiáng)

多態(tài)

  • 事物的多種形態(tài)
  • 沒(méi)有繼承就沒(méi)有多態(tài)
  • 代碼的體現(xiàn): 父類類型的指針指向子類對(duì)象
  • 好處: 如果函數(shù)\方法參數(shù)中使用的是父類類型, 可以傳入父類, 子類對(duì)象
  • 局限性: 父類類型的變量 不能 直接調(diào)用子類特有的方法,必須強(qiáng)轉(zhuǎn)為子類類型變量后, 才能直接調(diào)用子類特有的方法
  • 動(dòng)態(tài)綁定:
    • 動(dòng)態(tài)類型能使程序直到執(zhí)行時(shí)才確定對(duì)象的真實(shí)類型
    • 動(dòng)態(tài)類型綁定能使程序直到執(zhí)行時(shí)才確定要對(duì)那個(gè)對(duì)象調(diào)用的方法
    假設(shè) 子類 Dog 有一個(gè)特有的方法bark
    [dog bark];
    Animal *an = [Dog new];
    [(Dog*)an bark]; //把父類的指針,強(qiáng)制類型轉(zhuǎn)換    
    
    

9. 成員變量的作用域


  • @public 在任何地方都能直接訪問(wèn)對(duì)象的成員變量
  • @private 只能在當(dāng)前類的對(duì)象方法中直接訪問(wèn)(子類可以通過(guò)seter geter方法訪問(wèn)父類的私有的成員變量)
  • @protected 能在當(dāng)前類和子類的對(duì)象方法中直接訪問(wèn) (默認(rèn)是 protected)
  • @package 只要處在同一個(gè)框架中, 就能直接訪問(wèn)對(duì)象的成員變量(不常用)
    點(diǎn)語(yǔ)法使用注意
  • 點(diǎn)語(yǔ)法的本質(zhì)還是方法調(diào)用
  • p.age = 10; // [p setAge:10]
  • 引發(fā)死循環(huán)
    self.age = age; // [self setAge:age]
  • 私有成員變量
  • 寫在@implementation 中的成員變量,默認(rèn)就是私有成員變量扯俱,并且和利用@private 修飾的不太一樣书蚪,@implementation 中定義的成員變量在其他類中無(wú)法查看,也無(wú)法訪問(wèn)
    在@implementation 中定義的私有變量只能在本類中查看
  • 私有方法:只有實(shí)現(xiàn)沒(méi)有聲明迅栅,OC 中美有真正的私有方法殊校,因?yàn)?OC 是消息機(jī)制。私有方法外面不能訪問(wèn)读存,只能通過(guò)包裝成 sel 就可以訪問(wèn)

10. @property 用法


  • Property 編譯器指令

  • 生成setter 和 getter 方法聲明(未加強(qiáng)版)

    -(void)setAge:(int)age;
    -(int)age;
     @property int age;
    
  • @synthesize age = _age;

  • setter和getter實(shí)現(xiàn)中會(huì)訪問(wèn)成員變量_age, 如果成員變量_age不存在为流,就會(huì)自動(dòng)生成一個(gè)@private的成員變量_age

  • @synthesize age;

  • setter和getter實(shí)現(xiàn)中會(huì)訪問(wèn)@synthesize后同名成員變量age
    如果成員變量age不存在,就會(huì)自動(dòng)生成一個(gè)@private的成員變量age

  • 多個(gè)屬性可以通過(guò)一行@synthesize搞定,多個(gè)屬性之間用逗號(hào)連接

    @synthesize age = _age, number = _number, name = _name;
    
    
  • Property 增強(qiáng)

  • 只要利用一個(gè)@property就可以同時(shí)生成setter/getter方法的聲明和實(shí)現(xiàn)傳入的屬性賦值給_開(kāi)頭的成員變量

  • @property有一個(gè)弊端: 它只會(huì)生成最簡(jiǎn)單的getter/setter方法的聲明和實(shí)現(xiàn), 并不會(huì)對(duì)傳入的數(shù)據(jù)進(jìn)行過(guò)濾

  • 如果想對(duì)傳入的數(shù)據(jù)進(jìn)行過(guò)濾, 那么我們就必須重寫getter/setter方法如果不想對(duì)傳入的數(shù)據(jù)進(jìn)行過(guò)濾, 僅僅是提供一個(gè)方法給外界操作成員變量, 那么就可以使用@property

  • 注意: 如果沒(méi)有會(huì)自動(dòng)生成一個(gè)_開(kāi)頭的成員變量,自動(dòng)生成的成員變量是私有變量, 聲明在.m中,在其它文件中無(wú)法查看,但當(dāng)可以在本類中查看

  • 有就不生成让簿,沒(méi)有就生成

    • 如果重寫了setter方法, 那么property就只會(huì)生成getter方法
    • 如果重寫了getter方法, 那么property就只會(huì)生成setter方法
    • 如果同時(shí)重寫了getter/setter方法, 那么property就不會(huì)自動(dòng)幫我們生成私有的成員變量
  • @property(屬性修飾符) 數(shù)據(jù)類型 變量名稱;
    readwrite:代表生成 getter 和 setter 方法敬察,默認(rèn)就是
    readonly:代表只生成 getter 方法,(只讀)

  • 修改 getter 方法名(常用)
    程序員之間有一個(gè)約定, 一般情況下獲取BOOL類型的屬性的值, 我們都會(huì)將獲取的方法名稱改為isXXX

11. new alloc init 的基本用法及區(qū)別


  • alloc
  • 開(kāi)辟存儲(chǔ)空間
  • 將所有成員變量設(shè)為0
  • 返回當(dāng)前的對(duì)象地址
  • init
  • 初始化成員變量, 但是默認(rèn)情況下init的實(shí)現(xiàn)是什么都沒(méi)有做 2.返回初始化后的實(shí)例對(duì)象地址
  • alloc和 init 返回的地址是一樣的

12. id和 instancetype


  • 靜態(tài)類型和動(dòng)態(tài)類型
  • 靜態(tài)類型:將一個(gè)指針變量定義為特定類的對(duì)象時(shí),使用的是靜態(tài)類型,在編譯的時(shí)候就知道這個(gè)指針變量所屬的類,這個(gè)變量總是存儲(chǔ)特定類的對(duì)象尔当。
    Person *p = [Person alloc] init]]
  • 動(dòng)態(tài)類型:這一特性是程序直到執(zhí)行時(shí)才確定對(duì)象所屬的類
    id p = [[Person alloc] init];
  • Id
  • id 是一種通用的對(duì)象類型,它可以指向?qū)儆谌魏晤惖膶?duì)象,也可以理解為萬(wàn)能指針
  • id是動(dòng)態(tài)類型,所以可以通過(guò)id類型直接調(diào)用指向?qū)ο笾械姆椒? 編譯器不會(huì)報(bào)錯(cuò)
  • 優(yōu)點(diǎn)
    • 通過(guò)靜態(tài)數(shù)據(jù)類型定義變量, 不能調(diào)用子類特有的方法
    • 通過(guò)動(dòng)態(tài)數(shù)據(jù)類型定義變量, 可以調(diào)用子類特有的方法
    • 通過(guò)動(dòng)態(tài)數(shù)據(jù)類型定義的變量, 可以調(diào)用私有方法
  • 弊端: 由于動(dòng)態(tài)數(shù)據(jù)類型可以調(diào)用任意方法, 所以有可能調(diào)用到不屬于自己的方法, 而編譯時(shí)又不會(huì)報(bào)錯(cuò), 所以可能導(dǎo)致運(yùn)行時(shí)的錯(cuò)誤
  • 應(yīng)用場(chǎng)景
  • 多態(tài), 可以減少代碼量, 避免調(diào)用子類特有的方法需要強(qiáng)制類型轉(zhuǎn)換
  • 為了避免動(dòng)態(tài)數(shù)據(jù)類型引發(fā)的運(yùn)行時(shí)的錯(cuò)誤, 一般情況下如果使用動(dòng)態(tài)數(shù)據(jù)類型定義一個(gè)變量, 在調(diào)用這個(gè)變量的方法之前會(huì)進(jìn)行一次判斷, 判斷當(dāng)前變量是否能夠調(diào)用這個(gè)方法
id obj = [Student new];
[obj isKindOfClass:[Student class]]
//isKindOfClass , 判斷指定的對(duì)象是否是某一個(gè)類, 或者是某一個(gè)類的子類
  • instancetype
  • instancetype == id == 萬(wàn)能指針 == 指向一個(gè)對(duì)象
  • id在編譯的時(shí)候不能判斷對(duì)象的真實(shí)類型
  • instancetype在編譯的時(shí)候可以判斷對(duì)象的真實(shí)類型
  • id和instancetype除了一個(gè)在編譯時(shí)不知道真實(shí)類型, 一個(gè)在編譯時(shí)知道真實(shí)類型以外, 還有一個(gè)區(qū)別
  • id可以用來(lái)定義變量, 可以作為返回值, 可以作為形參
  • instancetype只能用于作為返回值
  • 注意: 以后但凡自定義構(gòu)造方法, 返回值盡量使用instancetype, 不要使用id

13. 構(gòu)造方法(- 開(kāi)頭的對(duì)象方法)


  • 用來(lái)初始化對(duì)象的方法.

  • 重寫構(gòu)造方法的注意:

  • 先調(diào)用父類的構(gòu)造方法.

  • 再進(jìn)行子類內(nèi)部的成員變量的初始化

  • 返回當(dāng)前對(duì)象的地址

     -(instancetype)init
     {
        // 注意: 不要把 = 號(hào)寫為 ==
        // 一定要將[super init]的返回值賦值給self
        if (self = [super init]) {
        // 初始化子類
        _age = 6;
        }
            return self;
    }    
    
    
  • 自定義構(gòu)造方法

  • 自己做自己的事情

  • 父類的屬性交給父類的方法來(lái)處理,子類的方法處理子類自己獨(dú)有的屬性

  • 自定義構(gòu)造方法必須以intiWith開(kāi)頭,并且’W’必須大寫

  • 類工廠方法:

  • 用于快速創(chuàng)建對(duì)象的類方法, 我們稱之為類工廠方法

  • 類工廠方法中主要用于 給對(duì)象分配存儲(chǔ)空間和初始化這塊存儲(chǔ)空間

  • 規(guī)范:

    • 一定是類方法 +
    • 方法名稱以類的名稱開(kāi)頭, 首字母小寫
    • 一定有返回值, 返回值是id/instancetype
    • 注意: 以后但凡自定義類工廠方法, 在類工廠方法中創(chuàng)建對(duì)象一定不要使用類名來(lái)創(chuàng)建莲祸,一定要使用self來(lái)創(chuàng)建
      return [[self alloc] init];

14. Category - 分類


  • 在不改變?cè)瓉?lái)類模型的前提下, 給類擴(kuò)充一些方法. 有2種方式 : 繼承 分類
  • 好處: 一個(gè)龐大的類可以分模塊開(kāi)發(fā), 一個(gè)龐大的類可以由多個(gè)人來(lái)編寫, 便于團(tuán)隊(duì)合作.
  • 使用注意:
  • 分類中寫property, 只會(huì)生成getter/setter方法的聲明, 不會(huì)生成實(shí)現(xiàn)和私有成員變量
  • Category 可以訪問(wèn)原始類的成員變量, 但不能添加變量, 只能添加方法. 如果想 添加變量, 可以考慮通過(guò)繼承創(chuàng) 建子類
  • Category 可以實(shí)現(xiàn)原始類的方法, 不推薦這么做, 因?yàn)樗翘鎿Q掉原始類的方 法, 這么做以后就不能訪問(wèn)原來(lái)的 方法.
  • 多個(gè)Category 中如果實(shí)現(xiàn)了相同的方法, 只有最后一個(gè)參與編譯的才會(huì)有效.
  • 方法調(diào)用的優(yōu)先級(jí) : 分類(最后參與編譯的分類優(yōu)先) —>原來(lái)類—>父類
  • 類擴(kuò)展(Extendsion)
  • 某個(gè)類擴(kuò)充一些私有的成員變量和方法
  • 寫在.m文件中
  • 英文名是Class Extension
  • 格式(俗稱匿名分類)
        @interface 類名 ()
        @end
        
    

15. 類的本質(zhì)(typedef struct objc_class * Class)


  • 類也是一個(gè)對(duì)象, 是 class 類型的對(duì)象, 簡(jiǎn)稱 “類對(duì)象”, 類名就代表著類對(duì)象, 每個(gè)類只有一個(gè)類對(duì)象
  • + load
  • + load : 在程序啟動(dòng)的時(shí)候會(huì)加載所有的類和分類, 并調(diào)用所有類和分類的 + load 方法,并且只會(huì)調(diào)用一次椭迎。
  • 加載順序 父類 → 子類→ 分類锐帜。不管程序運(yùn)行過(guò)程有沒(méi)有用到這個(gè)類, 都會(huì)調(diào)用 + load 方法。
  • + initialize
  • + initialize : 在第一次使用某個(gè)類時(shí)(比如創(chuàng)建對(duì)象等), 且只會(huì)調(diào)用一次 + initialize 方法.
  • 主要用于對(duì)某一個(gè)類一次性初始化
  • 一個(gè)類只會(huì)調(diào)用一次 + initialize方法, 先調(diào)用父類的, 再調(diào)用子類的
  • 獲取類對(duì)象的2種方式(獲取內(nèi)存中的類對(duì)象)
```
    Class c = [Person class]     // 類方法
    Person *p = [Person new];
    Class c1 = [p class];  // 對(duì)象方法

```
  • 類在內(nèi)存的表現(xiàn)
    • 實(shí)例對(duì)象 → 類對(duì)象(對(duì)象方法)→ 元類對(duì)象(類方法)→ 根元類 (isa 指向自己)
  • 元類保存了類方法的列表畜号。當(dāng)一個(gè)類方法被調(diào)用時(shí),元類會(huì)首先查找它本身是否有該類方法的實(shí)現(xiàn),如果沒(méi)有則該元類會(huì)向它的父類查找該方法,直到一直找到繼承鏈的頭缴阎。
  • 元類(metaclass)也是一個(gè)對(duì)象,那么元類的isa指針又指向哪里呢?為了設(shè)計(jì)上的完整,所有的元類的isa指針都會(huì)指向一個(gè)根元類(root metaclass)。
  • 根元類(root metaclass)本身的isa指針指向自己,這樣就行成了一個(gè)閉環(huán)简软。上面說(shuō)到,一個(gè)對(duì)象能夠接收的消息列表是保存在它所對(duì)應(yīng)的類中的药蜻。在實(shí)際編程中,我們幾乎不會(huì)遇到向元類發(fā)消息的情況,那它的isa 指針在實(shí)際上很少用到。不過(guò)這么設(shè)計(jì)保證了面向?qū)ο蟮母蓛?即所有事物都是對(duì)象,都有isa指針替饿。
  • 由于類方法的定義是保存在元類(metaclass)中,而方法調(diào)用的規(guī)則是,如果該類沒(méi)有一個(gè)方法的實(shí)現(xiàn),則向它的父類繼續(xù)查找语泽。所以為了保證父類的類方法可以在子類中可以被調(diào)用,所以子類的元類會(huì)繼承父類的元類,換而言之,類對(duì)象和元類對(duì)象有著同樣的繼承關(guān)系。
  • 如下圖 :


    Snip20150623_6.png

16. NSLog


  • 使用 NSLog 和 %@輸出某個(gè)類對(duì)象時(shí), 會(huì)調(diào)用類對(duì)象 + description 方法, 并拿到返回值(NSString *)進(jìn)行輸出
  • - description方法默認(rèn)返回對(duì)象的描述信息(默認(rèn)實(shí)現(xiàn)是返回類名和對(duì)象的內(nèi)存地址)
    • description方法是基類NSObject 所帶的方法. 使用NSLog輸出OC對(duì)象,意義就不是很大,因?yàn)槲覀儾⒉魂P(guān)心對(duì)象的內(nèi)存地址,比較關(guān)心的是對(duì)象內(nèi)部的一些成變量的值视卢。因此,會(huì)經(jīng)常重寫description方法,覆蓋description方法 的默認(rèn)實(shí)現(xiàn)
      -(NSString *) description
      {
              return [NSString stringWithFormat:@"age = %d", _age]
      }
      
      
  • + descrption 方法
  • 當(dāng)使用NSLog輸出該類的類對(duì)象的時(shí)候調(diào)用*/(不常用
  • 注意: 死循環(huán). 如果在 - description方法中使用 NSLog %@ 輸出self對(duì)象會(huì)引發(fā)死循環(huán)

17. SEL 基本使用


  • 代表方法的簽名踱卵,在類對(duì)象的方法列表中存儲(chǔ)著該簽名與方法代碼的對(duì)應(yīng)關(guān)系

  • 每個(gè)方法都有一個(gè)與之對(duì)應(yīng)的 SEL類型的對(duì)象

    • SEL 其實(shí)是對(duì)方法的一種包裝, 將方法包裝成一個(gè) SEL 類型的數(shù)據(jù), 去找對(duì)應(yīng)的方法地址, 進(jìn)而進(jìn)行調(diào)用
    • 注意:在這個(gè)操作過(guò)程中又緩存,第一次找的時(shí)候一個(gè)一個(gè)的找据过,非常耗性能惋砂,之后再用到的時(shí)候就直接使用
  • 對(duì)象是否實(shí)現(xiàn)了某個(gè)方法

    • - (BOOL) respondsToSelector: (SEL)selector 判斷實(shí)例是否實(shí)現(xiàn)這樣方法
    • + (BOOL)instancesRespondToSelector:(SEL)aSelector; (類對(duì)象)
  • 讓對(duì)象執(zhí)行某個(gè)方法

  • - (id)performSelector:(SEL)aSelector;

  • SEL 類型的定義 typedef struct objc_selector *SEL

    //SEL 對(duì)象的創(chuàng)建
     SEL s = @selector(test);
     SEL s2 = NSSelectorFromString(@"test”);
    // 將SEL對(duì)象轉(zhuǎn)為NSString對(duì)象
    NSString *str = NSStringFromSelector(@selector(test));
    Person *p = [Person new];
    // 每個(gè)類都有以個(gè)_cmd 代表當(dāng)前方法
    // 調(diào)用對(duì)象p的test方法
    [p  performSelector : @selector (test)];
    

18. 內(nèi)存管理


Automatic Reference Couting

  • 什么是自動(dòng)引用計(jì)數(shù)器
    • 每個(gè)OC對(duì)象都有自己的引用計(jì)數(shù)器绳锅,它是一個(gè)整數(shù)西饵,從字面上, 可以理解為”對(duì)象被引用的次數(shù)”
    • 也可以理解為: 它表示有多少人正在用這個(gè)對(duì)象
    • 占4個(gè)字節(jié)

Manul Refrence Counting

  • 什么是手動(dòng)引用計(jì)數(shù)?

    • 所有對(duì)象的內(nèi)容都需要我們手動(dòng)管理, 需要程序員自己編寫release/retain等代碼
  • 方法的基本使用

    • retain : 計(jì)數(shù)器 +1 , 會(huì)返回對(duì)象本身
    • release : 計(jì)數(shù)器 -1 , 沒(méi)有返回值(release并不代表銷毀對(duì)象, 僅僅是計(jì)數(shù)器-1
    • retainCount : 獲取當(dāng)前的計(jì)數(shù)器
  • 概念

    • 僵尸對(duì)象: 所占用內(nèi)存已經(jīng)被回收的對(duì)象, 僵尸對(duì)象不能再使用
    • 野指針: 指向僵尸對(duì)象(不可用內(nèi)存)的指針, 給野指針發(fā)送消息會(huì)報(bào)錯(cuò)(EXC_BAD_ACCES)
    • 空指針: 沒(méi)有指向任何東西的指針(儲(chǔ)存的東西是nil NULL 0), 給空指針發(fā)送消息不會(huì)報(bào)錯(cuò)
  • 內(nèi)存管理代碼規(guī)范
  • 只要調(diào)用了alloc, 必須有relese(autorelease), 如果對(duì)象不是通過(guò)alloc產(chǎn)生的, 就不需要release
  • set方法的代碼規(guī)范
    • 基本數(shù)據(jù)類型: 直接復(fù)制
    -(void)setAge:(int)age
        {
        _age = age;
        }        
    ```
     -  OC對(duì)象類型
    ```
    -(void)setCar:(Car *)car
    {
    // 先判斷是不是新傳進(jìn)來(lái)對(duì)象
        if( car != _car)
        {
    // 對(duì)舊對(duì)象做一次release
        [_car release]
    // 對(duì)新對(duì)象做一次retain
        _car = [car retain]
        }
    }
    ```
    
  • dealloc方法的代碼規(guī)范
    • 對(duì)self(當(dāng)前)所擁有的其他對(duì)象做一次release
    • 當(dāng)一個(gè)對(duì)象要被回收的時(shí)候, 就會(huì)調(diào)用
    • 一定要調(diào)用[super dealloc], 這句調(diào)用放在最后面

@Property 參數(shù)

  • set 方法內(nèi)存管理相關(guān)的參數(shù)
    • retain : release 舊值 , retain 新值 (適用于OC對(duì)象類型)
    • assign : 直接賦值(默認(rèn), 適用于非OC對(duì)象類型)
    • copy : release 舊值, copy 新值
  • 是否要生成set方法
    • readwrite : 同時(shí)生成setter 和 getter的聲明, 實(shí)現(xiàn)(默認(rèn))
    • readonly : 只會(huì)生成getter的聲明, 實(shí)現(xiàn)
  • 多線程管理
    • nonatomic : 性能高 (一般就用這個(gè))
    • atomic : 性能低(默認(rèn))
  • setter 和 getter方法的名稱
    • setter : 決定了set方法的名稱, 一定要有個(gè)冒號(hào) :
    • getter : 決定了get方法的名稱(一般用在BOOL類型)

@Class(循環(huán)引用)

  • 僅僅告訴編譯器,某個(gè)名稱是一個(gè)類

  • 開(kāi)發(fā)中引用一個(gè)類的規(guī)范

    • 在.h 文件中用@class 來(lái)聲明類
    • 在.m 文件中用#import 來(lái)包含類的所有東西
  • 和#import 的區(qū)別(面試)

    • import會(huì)包含引用類的所有信息(內(nèi)容),包括引用類的變量和方法
    • @class僅僅是告訴編譯器有這么一個(gè)類, 具體這個(gè)類里有什么信息, 完全不知
  • 總結(jié):

    • 如果都在.h中import, 假如A拷貝了B, B拷貝了C , 如果C被修改了, 那么B和A都需要重新拷貝. 因?yàn)镃修改了那么B就會(huì)重新拷貝, 而B重新拷貝之后相當(dāng)于B也被修改了, 那么A也需要重新拷貝. 也就是說(shuō)如果都在.h中拷貝, 只要有間接關(guān)系都會(huì)重新拷貝
    • 如果在.h中用@class, 在.m中用import, 那么如果一個(gè)文件發(fā)生了變化, 只有和這個(gè)文件有直接關(guān)系的那個(gè)文件才會(huì)重新拷貝
    • 所以在.h中用@class可以提升編譯效率
  • 兩端循環(huán)引用(面試)

  • retain
    * 比如A對(duì)象retain了B對(duì)象鳞芙,B對(duì)象retain了A對(duì)象眷柔,這樣會(huì)導(dǎo)致A對(duì)象和B對(duì)象永遠(yuǎn)無(wú)法釋放期虾。
    * 當(dāng)兩端互相引用時(shí),應(yīng)該一端用retain驯嘱、一端用assign镶苞。

  • import
    * 如果兩個(gè)類相互(#import<>)拷貝, 例如A拷貝B, B拷貝A, 這樣會(huì)報(bào)錯(cuò)
    - 如何解決: 在.h中用@class, 在.m中用import
    - 因?yàn)槿绻?h中都用import, 那么A拷貝B, B又拷貝A, 會(huì)形成死循環(huán)
    - 如果在.h中用@class, 那么不會(huì)做任何拷貝操作, 而在.m中用import只會(huì)拷貝對(duì)應(yīng)的文件, 并不會(huì)形成死循環(huán)

@ autorelease基本用法

  • 會(huì)將對(duì)象放到一個(gè)自動(dòng)釋放池中,并且會(huì)返回對(duì)象本身
  • 當(dāng)自動(dòng)釋放池被銷毀時(shí)鞠评, 會(huì)對(duì)池子里面的所有對(duì)象做一次release 操作
  • 調(diào)用完@autorelease 方法后茂蚓,對(duì)象計(jì)數(shù)器不變
  • @autorelease 的好處
    • 不用關(guān)心對(duì)象釋放的時(shí)間
    • 不用關(guān)心什么時(shí)候調(diào)用 release
  • @autorelease 使用注意
    • 占用內(nèi)存較大的對(duì)象不要隨便用 autorelease
    • 占用內(nèi)存較小的對(duì)象使用 autorelease,沒(méi)有太大影響(影響:不能控制對(duì)象的釋放時(shí)間)
  • 錯(cuò)誤寫法
    • alloc 之后調(diào)用了 autorelease 剃幌,又調(diào)用 release
      Person *p = [[[Person alloc] init] autorelease];
      [p release];
    • 連續(xù)調(diào)用autorelease(野指針錯(cuò)誤聋涨,每個(gè)autorelease 釋放時(shí)都會(huì)調(diào)用 release)
      Person *p = [[[[Person alloc] init] auturelease] autorelease]
  • 系統(tǒng)自帶方法里面沒(méi)有alloc、new负乡、copy牍白,說(shuō)明返回的對(duì)象是autorelease的
    • 開(kāi)發(fā)中經(jīng)常會(huì)提供一些類方法,快速創(chuàng)建一個(gè)已經(jīng)autorelease過(guò)的對(duì)象
    • 創(chuàng)建對(duì)象時(shí)不要直接用類名敬鬓,一般用 self
  + (id)person
   {
       return [[[self alloc] init] autorelease];
   }
  • 自動(dòng)釋放池

  • 在 IOS 程序運(yùn)行中淹朋,會(huì)創(chuàng)建無(wú)數(shù)個(gè)池子笙各。這些池子都是以“椂ご穑”結(jié)構(gòu)存在(先進(jìn)后出,“杯子”)

  • 當(dāng)一個(gè)對(duì)象調(diào)用 autorelease 方法時(shí)杈抢,會(huì)將這個(gè)對(duì)象放到棧頂?shù)尼尫懦?(”棧頂“ 相當(dāng)于杯子底)

  • 集合對(duì)象的內(nèi)存管理

    • 當(dāng)把一個(gè)對(duì)象添加到集合中時(shí),這個(gè)對(duì)象會(huì)做了一次retain操作,計(jì)數(shù)器會(huì)+1
    • 當(dāng)一個(gè)集合被銷毀時(shí),會(huì)對(duì)集合里面的所有對(duì)象做一次release操作,計(jì)數(shù)器會(huì)-1
    • 當(dāng)一個(gè)對(duì)象從集合中移除時(shí),這個(gè)對(duì)象會(huì)一次release操作,計(jì)數(shù)器會(huì)-1

ARC

  • ARC 的判斷準(zhǔn)則:主要沒(méi)有強(qiáng)指針指向?qū)ο笫颍蜁?huì)釋放對(duì)象

  • 指針的2種類型

  • 強(qiáng)指針:_strong 默認(rèn)情況,所有指針都是強(qiáng)指針

  • 弱指針:_weak

    • _weak Person *p = [[Person alloc] init] 錯(cuò)誤寫法惶楼,沒(méi)有意義的寫法右蹦,一創(chuàng)建就釋放
  • ARC 特點(diǎn)

    • 不允許調(diào)用 release、retain歼捐、retainCount
    • 允許重寫 dealloc何陆,但是不允許調(diào)用[super dealloc]
    • @property 的參數(shù)
    • strong : 成員變量是強(qiáng)指針(適用于 OC 對(duì)象類型)
    • weak : 成員變量是弱指針(適用于 OC 對(duì)象類型)
    • assign:適用于非 OC 對(duì)象
  • 循環(huán)引用
    一端用:strong,另一端用:weak

  • 在Compiler Flags一列加上-fno-objc-arc就表示禁止這個(gè).m文件的ARC

  • mrc 可以轉(zhuǎn) arc 豹储,系統(tǒng)轉(zhuǎn)換

19. copy


  • copy的基本原則
    • 因?yàn)榭截愐笮薷脑瓉?lái)的對(duì)象不能影響到拷貝出來(lái)得對(duì)象
    • 修改拷貝出來(lái)的對(duì)象也不能影響到原來(lái)的對(duì)象, 所以需要生成一個(gè)新的對(duì)象
    • 互不影響
  • copy的使用
    • 實(shí)現(xiàn)拷貝的方法有2個(gè)
      • copy:返回不可變副本
      • mutableCopy:返回可變副本
  • 普通對(duì)象實(shí)現(xiàn)拷貝的步驟
    • 遵守NSCopying協(xié)議
    • 實(shí)現(xiàn)-copyWithZone:方法
      • 創(chuàng)建新對(duì)象
      • 給新對(duì)象的屬性賦值

20. Block


  • block訪問(wèn)外面變量
    • block內(nèi)部可以訪問(wèn)外面的變量
    • 默認(rèn)情況下贷盲,block內(nèi)部不能修改外面的局部變量
    • 給局部變量加上__block關(guān)鍵字,這個(gè)局部變量就可以在block內(nèi)部修改
  • 利用typedef定義block類型
    typedef int (^MyBlock)(int, int);
    // 以后就可以利用MyBlock這種類型來(lái)定義block變量
  • block是存儲(chǔ)在堆中還是棧中
    • 默認(rèn)情況下block存儲(chǔ)在棧中, 如果對(duì)block進(jìn)行一個(gè)copy操作, block會(huì)轉(zhuǎn)移到堆中
    • 如果block在棧中, block中訪問(wèn)了外界的對(duì)象, 那么不會(huì)對(duì)對(duì)象進(jìn)行retain操作
    • 但是如果block在堆中, block中訪問(wèn)了外界的對(duì)象, 那么會(huì)對(duì)外界的對(duì)象進(jìn)行一次retain
    • 如果在block中訪問(wèn)了外界的對(duì)象, 一定要給對(duì)象加上__block, 只要加上了__block, 哪怕block在堆中, 也不會(huì)對(duì)外界的對(duì)象進(jìn)行retain
    • 如果是在ARC開(kāi)發(fā)中就需要在前面加上__weak
    Person *p = [Person new];
    __weak Person *weakP = p;
    void (^myBlock) () = ^{
        
        weakP.age = 10;
    };
    myBlock();
    NSLog(@"age = %li", p.age);
    
    

21. Protocol


  • 協(xié)議

  • @protocol 協(xié)議名稱 < NSObeject >
    // 方法聲明列表....
    @end

  • 如何遵守協(xié)議

  • 類遵守協(xié)議
    @interface 類名 : 父類名 <協(xié)議名稱1, 協(xié)議名稱2>
    @end

  • 協(xié)議遵守協(xié)議
    @protocol 協(xié)議名稱 <其他協(xié)議名稱1, 其他協(xié)議名稱2>
    @end

  • 協(xié)議中方法聲明的關(guān)鍵字

  • @required (默認(rèn)): 要求實(shí)現(xiàn)剥扣,如果沒(méi)有實(shí)現(xiàn)巩剖,會(huì)發(fā)出警告

  • @optional: 不要求實(shí)現(xiàn),不會(huì)有警告

  • 定義一個(gè)變量的時(shí)候钠怯,限制這個(gè)變量保存的對(duì)象遵守某個(gè)協(xié)議

  • 如果沒(méi)有遵守對(duì)應(yīng)的協(xié)議佳魔,編譯器會(huì)警告

    類名<協(xié)議名稱> *變量名;
    id<協(xié)議名稱> 變量名;
    NSObject<MyProtocol> *obj;
    id<MyProtocol> obj2;
    
  • @property中聲明的屬性也可用做一個(gè)遵守協(xié)議的限制

    @property (nonatomic, strong) 類名<協(xié)議名稱> *屬性名;
    @property (nonatomic, strong) id<協(xié)議名稱> 屬性名;
    @property (nonatomic, strong) Dog<MyProtocol> *dog;
    @property (nonatomic, strong) id<MyProtocol> dog2;
    
  • 協(xié)議可用定義在單獨(dú).h文件中,也可用定義在某個(gè)類中

  • 如果這個(gè)協(xié)議只用在某個(gè)類中晦炊,應(yīng)該把協(xié)議定義在該類中

  • 如果這個(gè)協(xié)議用在很多類中鞠鲜,就應(yīng)該定義在單獨(dú)文件中

  • 分類可用定義在單獨(dú).h和.m文件中宁脊,也可用定義在原來(lái)類中

  • 一般情況下,都是定義在單獨(dú)文件

  • 定義在原來(lái)類中的分類镊尺,只要求能看懂語(yǔ)法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末朦佩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子庐氮,更是在濱河造成了極大的恐慌语稠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弄砍,死亡現(xiàn)場(chǎng)離奇詭異仙畦,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)音婶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門慨畸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人衣式,你說(shuō)我怎么就攤上這事寸士。” “怎么了碴卧?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵弱卡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我住册,道長(zhǎng)婶博,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任荧飞,我火速辦了婚禮凡人,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叹阔。我一直安慰自己挠轴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布耳幢。 她就那樣靜靜地躺著岸晦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帅掘。 梳的紋絲不亂的頭發(fā)上委煤,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音修档,去河邊找鬼碧绞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吱窝,可吹牛的內(nèi)容都是我干的讥邻。 我是一名探鬼主播迫靖,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兴使!你這毒婦竟也來(lái)了系宜?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤发魄,失蹤者是張志新(化名)和其女友劉穎盹牧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體励幼,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汰寓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苹粟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片有滑。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嵌削,靈堂內(nèi)的尸體忽然破棺而出毛好,到底是詐尸還是另有隱情,我是刑警寧澤苛秕,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布肌访,位于F島的核電站,受9級(jí)特大地震影響想帅,放射性物質(zhì)發(fā)生泄漏场靴。R本人自食惡果不足惜啡莉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一港准、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咧欣,春花似錦浅缸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至哮兰,卻和暖如春毛萌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喝滞。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工阁将, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人右遭。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓做盅,卻偏偏與公主長(zhǎng)得像缤削,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吹榴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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