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

Objective-C

1. import的用法


  • 拷貝文件內(nèi)容
    可以自動防止文件的內(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(用到的時候才加)
  • 運行: ./a.out
  • 主頭文件
    主頭文件:最主要的頭文件,名字一般跟框架名稱一樣,包含了框架中的所有其他頭文件
  • Foundation框架的主頭文件名稱就是Foundation.h
    只需要包含F(xiàn)oundation框架主頭文件,就可以使用整個框架的東西

2. 對象方法和類方法


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

3. 成員變量和局部變量


  • 成員變量:

    • 寫在類聲明的大括號中的變量, 我們稱之為 成員變量(屬性, 實例變量)成員變量只能通過對象來訪問
    • 注意: 成員變量不能離開類,,離開類之后就不是成員變量,成員變量不能在定義的同時進行初始化
    • 存儲: 堆(當(dāng)前對象對應(yīng)的堆的存儲空間中)
    • 存儲在堆中的數(shù)據(jù), 不會被自動釋放, 只能程序員手動釋放
  • 局部變量:

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

    • 作用域: 從定義的那一行開始, 一直到遇到大括號或者return
    • 局部變量可以先定義再初始化, 也可以定義的同時初始化
    • 存儲 : 棧
    • 存儲在棧中的數(shù)據(jù)有一個特點, 系統(tǒng)會自動給我們釋放
  • 全局變量

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

4. 方法和函數(shù)


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

5. setter 和 getter 用法簡介


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

6. self 的基本使用


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

7. super 基本使用


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

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

封裝

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

繼承

  • 父類必須聲明在子類的前面
  • 不允許子類和父類擁有相同名稱的成員變量, 因為子類繼承父類,子類將會擁有父類的所有成員變量,若在子類中定義父類同名成員變量 屬于重復(fù)定義。
  • 調(diào)用某個對象的方法時, 優(yōu)先去當(dāng)前類中找, 如果么有, 去父類中找
  • 基類的私有屬性能被繼承, 不能在子類中訪問。
  • OC中的繼承是單繼承:也就是說一個類只能一個父類, 不能繼承多個父類
  • 缺點:耦合性太強

多態(tài)

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

9. 成員變量的作用域


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

10. @property 用法


  • Property 編譯器指令

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

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

  • setter和getter實現(xiàn)中會訪問成員變量_age, 如果成員變量_age不存在,就會自動生成一個@private的成員變量_age

  • @synthesize age;

  • setter和getter實現(xiàn)中會訪問@synthesize后同名成員變量age
    如果成員變量age不存在,就會自動生成一個@private的成員變量age

  • 多個屬性可以通過一行@synthesize搞定,多個屬性之間用逗號連接

    @synthesize age = _age, number = _number, name = _name;
    
    
  • Property 增強

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

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

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

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

  • 有就不生成,沒有就生成

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

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

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


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

12. id和 instancetype


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

13. 構(gòu)造方法(- 開頭的對象方法)


  • 用來初始化對象的方法.

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

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

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

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

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

  • 自己做自己的事情

  • 父類的屬性交給父類的方法來處理,子類的方法處理子類自己獨有的屬性

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

  • 類工廠方法:

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

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

  • 規(guī)范:

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

14. Category - 分類


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

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


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

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


    Snip20150623_6.png

16. NSLog


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

17. SEL 基本使用


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

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

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

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

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

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

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

18. 內(nèi)存管理


Automatic Reference Couting

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

Manul Refrence Counting

  • 什么是手動引用計數(shù)?

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

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

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

@Property 參數(shù)

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

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

  • 僅僅告訴編譯器,某個名稱是一個類

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

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

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

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

  • retain
    * 比如A對象retain了B對象,B對象retain了A對象,這樣會導(dǎo)致A對象和B對象永遠無法釋放。
    * 當(dāng)兩端互相引用時,應(yīng)該一端用retain、一端用assign。

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

@ autorelease基本用法

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

  • 在 IOS 程序運行中,會創(chuàng)建無數(shù)個池子。這些池子都是以“棧”結(jié)構(gòu)存在(先進后出,“杯子”)

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

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

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

ARC

  • ARC 的判斷準(zhǔn)則:主要沒有強指針指向?qū)ο螅蜁尫艑ο?/p>

  • 指針的2種類型

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

  • 弱指針:_weak

    • _weak Person *p = [[Person alloc] init] 錯誤寫法,沒有意義的寫法,一創(chuàng)建就釋放
  • ARC 特點

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

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

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

19. copy


  • copy的基本原則
    • 因為拷貝要求修改原來的對象不能影響到拷貝出來得對象
    • 修改拷貝出來的對象也不能影響到原來的對象, 所以需要生成一個新的對象
    • 互不影響
  • copy的使用
    • 實現(xiàn)拷貝的方法有2個
      • copy:返回不可變副本
      • mutableCopy:返回可變副本
  • 普通對象實現(xiàn)拷貝的步驟
    • 遵守NSCopying協(xié)議
    • 實現(xiàn)-copyWithZone:方法
      • 創(chuàng)建新對象
      • 給新對象的屬性賦值

20. Block


  • block訪問外面變量
    • block內(nèi)部可以訪問外面的變量
    • 默認(rèn)情況下,block內(nèi)部不能修改外面的局部變量
    • 給局部變量加上__block關(guān)鍵字,這個局部變量就可以在block內(nèi)部修改
  • 利用typedef定義block類型
    typedef int (^MyBlock)(int, int);
    // 以后就可以利用MyBlock這種類型來定義block變量
  • block是存儲在堆中還是棧中
    • 默認(rèn)情況下block存儲在棧中, 如果對block進行一個copy操作, block會轉(zhuǎn)移到堆中
    • 如果block在棧中, block中訪問了外界的對象, 那么不會對對象進行retain操作
    • 但是如果block在堆中, block中訪問了外界的對象, 那么會對外界的對象進行一次retain
    • 如果在block中訪問了外界的對象, 一定要給對象加上__block, 只要加上了__block, 哪怕block在堆中, 也不會對外界的對象進行retain
    • 如果是在ARC開發(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)): 要求實現(xiàn),如果沒有實現(xiàn),會發(fā)出警告

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

  • 定義一個變量的時候,限制這個變量保存的對象遵守某個協(xié)議

  • 如果沒有遵守對應(yīng)的協(xié)議,編譯器會警告

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

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

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

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

  • 分類可用定義在單獨.h和.m文件中,也可用定義在原來類中

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

  • 定義在原來類中的分類,只要求能看懂語法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,908評論 2 372

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