OC語言瘋狂講義學習筆記

躍然發表於2015-06-01

1、關於nil和Nil及NULL的區別:

nil: A null pointer to an Objective-C object. ( #define nil ((id)0) ) nil 是一個物件值。
Nil: A null pointer to an Objective-C class.
NULL: A null pointer to anything else. ( #define NULL ((void *)0) ) NULL是一個通用指標(泛型指標)。
NSNull: A class defines a singleton object used to represent null values in collection objects (which don’t allow nil values).
[NSNull null]: The singleton instance of NSNull.
[NSNull null]是一個物件,他用在不能使用nil的場合。

2、避免使用殭屍物件的方法

為了防止不小心呼叫了殭屍物件,可以將物件賦值nil(物件的空值)

殭屍物件.png

3、物件的記憶體洩露

記憶體洩露1.png
記憶體洩露1.png
記憶體洩露2.png
記憶體洩露3_1.png
記憶體洩露3_2.png

4、@property 引數

property引數.png

記憶體管理相關引數:
記憶體管理相關引數.png
assign.png
assign_2.png
retain_1.png
retain_2.png
retain_3.png
retain_3.png
retain_4.png
proPerty引數二.png
property_set.png
property_get.png

5、@class的使用

作用

可以簡單地引用一個類
#### 簡單使用
@class Dog; //類的引入
僅僅是告訴編譯器: Dog是一個類; 並不會包含Dog這個類的所有內容

具體使用

在.h檔案中使用@class引用一個類 在.m檔案中使用#import包含這個類的.h檔案

通常引用一個類有兩種辦法:
一種是通過#import方式引入;另一種是通過@class引入; 這兩種的方式的區別在於:

1)#import方式會包含被引用類的所有資訊,包括被引用類的變數和方法;@class方式只是告訴 編譯器在A.h檔案中 B *b 只是類的宣告,具體這個類裡有什麼資訊,這裡不需要知道,等實現文 件中真正要用到時,才會真正去檢視B類中資訊;

2)使用@class方式由於只需要只要被引用類(B類)的名稱就可以了,而在實現類由於要用到被 引用類中的實體變數和方法,所以需要使用#import來包含被引用類的標頭檔案;

3)通過上面2點也很容易知道在編譯效率上,如果有上百個標頭檔案都#import了同一 個檔案,或 者這些檔案依次被#improt(A->B, B->C,C->D…),一旦最開始的標頭檔案稍有改動,後面引用到這 個檔案的所有類都需要重新編譯一遍,這樣的效率也是可想而知的,而相對來 講,使用@class方 式就不會出現這種問題了;

所以:我們實際開發中儘量在.h標頭檔案中使用@class

4)對於迴圈依賴關係來說,比方A類引用B類,同時B類也引用A類,B類的程式碼:

recycle.png

作用上的區別

import會包含引用類的所有資訊(內容), 包括引用類的變數和方法 @class僅僅是告訴編譯器有這麼一個類, 具體這個類裡有什麼資訊, 完全不知

效率上的區別

如果有上百個標頭檔案都#import了同一個檔案,或者這些檔案依次被#import,那麼一旦最開始的頭 檔案稍有改動,後面引用到這個檔案的所有類都需要重新編譯一遍 , 編譯效率非常低 相對來講,使用@class方式就不會出現這種問題了

6、迴圈引用

迴圈retain的場景

recycle.png
比如A物件retain了B物件,B物件retain了A物件 迴圈retain的弊端 這樣會導致A物件和B物件永遠無法釋放

迴圈retain的解決方案

當兩端互相引用時,應該一端用retain、一端用assign

7、NSString 類的記憶體管理問題

1)、NSString 等Foundation框架中類的記憶體管理

記憶體管理.png

先看看以下這幾種寫法:

NSString *testStr1 = @”a”;
NSString *testStr2 = [NSString stringWithString:@”a”];
NSString *testStr3 = [NSString stringWithFormat:@”b”];
NSString *testStr4 = [[NSString alloc] initWithString:@”c”];
NSString *testStr5 = [[NSString alloc] initWithFormat:@”d”];
NSString *testStr6 = [[NSString alloc] init];

NSLog(@”testStr1 ->%p”,testStr1);
NSLog(@”testStr2 ->%p”,testStr2);
NSLog(@”testStr3 ->%p”,testStr3);
NSLog(@”testStr4 ->%p”,testStr4);
NSLog(@”testStr5 ->%p”,testStr5);
NSLog(@”testStr6 ->%p”,testStr6);

記憶體管理_2.png

通過對比地址可以看到,從上可以看出,testStr1,testStr2,testStr4都是在一個記憶體區域,也 就是常量記憶體區,

1---> NSString *str = [[NSString alloc] initWithString:@"ABC"]; 
2---> str = @"123";
3---> [str release];
4---> NSLog(@"%@",str);

首先,我們們先對這段程式碼進行分析。
第一句 宣告瞭一個NSString型別的例項 str, 並將其初始化init後賦值為@”ABC” 第二行,將str的指標指向了一個常量@”123”。 理論上講在第一行初始化的@”ABC”沒有任何任何 指標指向了。 所以造成了記憶體洩露
然後第三行, 將str的引用計數-1
第四行輸出str的值 為123.
首先回答為什麼不會崩潰, 因為第三行的release 實際上是release了一個常量@”123” 而作為 常量,其預設的引用計數值是很大的(100k+)
NSLog(@”retainCount = %tu”,[@”123” retainCount]);
最終的輸出值會是一個很大很大的數。 所以單單一個release是不會將其釋放掉的。
然後再回答這樣會不會造成記憶體洩露。
其實…………理論上講 會!
但是實際上,Objective-C對NSString型別有特殊照顧。所有的NSString的引用計數器預設初始值 都會非常非常大。

2)、危險的用法

while ([a retainCount] > 0) {
         [a release];
} 

如果執行結果正確,那麼這是多麼幸運的一個人啊!

8、自動釋放池及autorelease介紹

自動釋放池

(1)在iOS程式執行過程中,會建立無數個池子,這些池子都是以棧結構(先進後出)存在的。 (2)當一個物件呼叫autorelease時,會將這個物件放到位於棧頂的釋放池中

自動釋放池的建立方式

(1)iOS 5.0以前的建立方式

NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
 `````````````````
[pool release];//[pool drain];用於mac

(2)iOS5.0以後

@autoreleasepool
{//開始代表建立自動釋放池 
      ·······
}//結束代表銷燬自動釋放池

autorelease

是一種支援引用計數的記憶體管理方式
它可以暫時的儲存某個物件(object),然後在記憶體池自己的排幹(drain)的時候對其中的每個 物件傳送release訊息 注意,這裡只是傳送release訊息,如果當時的引用計數(reference-counted)依然不為0,則該 物件依然不會被釋放。可以用該方法來儲存某個物件,也要注意儲存之後要釋放該物件。

為什麼會有autorelease?

(1)不需要再關心物件釋放的時間
(2)不需要再關心什麼時候呼叫release

autorelease何時釋放?

對於autorelease pool本身,會在如下兩個條件發生時候被釋放
1)手動釋放Autorelease pool
2)Runloop結束後自動釋放
對於autorelease pool內部的物件
在引用計數的retain == 0的時候釋放。release和autorelease pool 的 drain都會觸發retain– 事件。

9、Block

一、靜態變數和全域性變數 在加和不加 __block都會直接引用變數地址。也就意味著可以修
改變數的值。在沒有加__block 引數的情況下。
• 全域性block和棧block區別為是否引用了外部變數,堆block則是對棧block copy得來。對全域性block
copy 不會有任何作用,返回的依然是全域性block。
二, 常量變數(NSString *a = @”hello”;a 為常量變數,@“hello”為常量。)—–不 加__block型別 block 會引用常量的地址(淺拷貝)。加__block型別 block會去引用常量變 量(如:a變數,a = @”abc”.可以任意修改a 指向的內容。)的地址。

相關文章