iT邦幫忙

0

iOS APP 開發 OC 第七天, 對象在內存中的儲存

tags: OC 30 day

1. 內存中的五大區域:

棧 儲存局部變量。
堆 工程師手動申請的字節空間 malloc calloc realloc函數。
BSS段 儲存未被初始化的全局變量,靜態變量。
數據段(常量區) 儲存已被初始化的全局,靜態變量,常量數據。
代碼段 儲存代碼。

2. 類加載

  1. 在創建對象時,肯定是要訪問類的。
  2. 聲明一個類的指針變量也會訪問類。

當程序運行期間,當某個類第一次被訪問到的時候,會將這個類儲存到內存中的代碼段區域。這個過程叫做類加載。
只有類在第一次被訪問時,才會做類加載。
一但類被加載到代碼段以後,直到程序結束的時候才會被釋放掉。

3. 對象在內存當中究竟是如何儲存的?

假設下面這段寫在函數之中

Person *p1 = [Person new];
  1. Person *p1; 會在棧內存當中申請一塊空間,在棧內存中聲明一個Person類型的指針變量p1。p1是一個指針變量,那麼只能儲存地址。
  2. [Person new]; 真正在內存中創建對象的是這段代碼。
    new做的事情:
    a. 在堆內存中申請一塊合適大小的空間。
    b. 在這個空間中根據類的模板創建對象。
    類模板中定義了什麼屬性,就把這些屬性一次聲明在對象之中,對象中還有另外一個屬性,就是isa是一個指針(指向代碼段)。
    c. 初始化對象的屬性
    如果屬性的類型是基本數據類型,那麼就服值為0。
    如果屬性的類型是C語言的指針類型,那麼就服值為NULL。
    如果屬性的類型是OC的類指針類型,那麼就賦值為nil。
    d. 返回對象的地址

我們來驗證看看

@interface Person : NSObject
{
    @public
    NSString *_name;
    int _age;
}
-(void)sayHi;
@end
@implementation Person
-(void)sayHi
{
    NSLog(@"大家好,我叫%@,我今年%d歲",_name,_age);
}
@end




int main(int argc, char * argv[]) {
    Person *p1 = [Person new];
    NSLog(@"p1 = %p",p1);
    return  0;
}

首先來執行這一段代碼,

我們會發現 *p1 的確是一個地址
那麼 p1的對象還有一個isa指針。

下一個斷點來看看

我們發現p1對象裡面確實有一個isa的指針,但是我們無法對他進行訪問。

補充

  1. 對象當中只有屬性沒有方法,自己的類的屬性外加一個isa指針指向代碼段中的類。
  2. 如何訪問對象的屬性:指針名->屬性名; 根據指針,找到指針指向的對象,再找到對象中的屬性來訪問。
  3. 如何調用方法:[指針名 方法名]; 先根據指針名找到對象,對象發現要調用方法,再根據對象的isa指針找到類。然後調用類裡的方法。
  4. 為什麼不把方法儲存在對象之中?因為每一個對象的方法的代碼實現都是一模一樣的,沒有必要為每一個對象都保存一個方法,這樣太浪費空間了。


不同的對象,指向的是同一個記憶體
6. 對象的屬性默認值:如果我們創建一個對象,沒有為對象的屬性復職,那麼這葛對象的屬性是有值的。如果屬性的類型是基本的數據類型,默認值是0,如果屬性的類型是C語言的指針類型,那麼就服值為NULL。如果屬性的類型是OC的類指針類型,那麼就賦值為nil。


1 則留言

0
ytyubox
iT邦新手 5 級 ‧ 2020-12-29 12:40:00

補充 isa
https://stackoverflow.com/a/3405240/10172299

Under the hood, Objective-C objects are basically C structs. Each one contains a field called isa, which is a pointer to the class that the object is an instance of (that's how the object and Objective-C runtime knows what kind of object it is).

isa 是一種類別記號,透過在 C structure 內固定紀錄這個值,使得型別系統可以被記錄,尤其在 subclass 的時候使用 super 時使用

我要留言

立即登入留言