iOS中編寫(xiě)高效能結(jié)構(gòu)體的7個(gè)要點(diǎn)

結(jié)構(gòu)體是C/C++兩種語(yǔ)言中的基礎(chǔ)語(yǔ)法, C語(yǔ)言中的結(jié)構(gòu)體只是一個(gè)存粹的數(shù)據(jù)集合類(lèi)型的描述政恍,它只有數(shù)據(jù)成員而沒(méi)有成員方法鸠补。C++中的結(jié)構(gòu)體則被賦予為一個(gè)類(lèi)定義的角色膘滨,它可以有數(shù)據(jù)成員也可以有成員方法耀鸦。OC語(yǔ)言源自于C語(yǔ)言寝衫,它是面向?qū)ο蟮腃語(yǔ)言顷扩,自然結(jié)構(gòu)體的概念就和C語(yǔ)言中的定義保持一致。

結(jié)構(gòu)體中的數(shù)據(jù)成員可以是基本類(lèi)型慰毅,也可以是數(shù)組隘截,也可以是指針,還可以是其他的結(jié)構(gòu)體汹胃。下面是一個(gè)結(jié)構(gòu)體的定義示例:

struct Student {
  bool sex;
  short int age;
  char *address;
  float grade;
  char  name[9];
};

結(jié)構(gòu)體尺寸

一個(gè)被經(jīng)常討論的問(wèn)題就是求結(jié)構(gòu)體的尺寸(Size)大小婶芭,也就是結(jié)構(gòu)體實(shí)例占用的內(nèi)存字節(jié)數(shù)。結(jié)構(gòu)體的尺寸受操作系統(tǒng)字長(zhǎng)着饥、編譯器犀农、對(duì)齊方式等眾多因素的影響。因此要確認(rèn)一個(gè)結(jié)構(gòu)體的尺寸時(shí)如果沒(méi)有上述的約束前提則是沒(méi)有統(tǒng)一結(jié)果的宰掉。一般情況下計(jì)算結(jié)構(gòu)體尺寸大小有如下規(guī)則:

  1. 結(jié)構(gòu)體中每個(gè)數(shù)據(jù)成員的偏移位置是數(shù)據(jù)成員本身尺寸的倍數(shù)呵哨。
  2. 結(jié)構(gòu)體的尺寸是最大基礎(chǔ)類(lèi)型數(shù)據(jù)成員尺寸的倍數(shù)赁濒。
  3. 如果有結(jié)構(gòu)體嵌套時(shí),被嵌套的結(jié)構(gòu)體成員的偏移位置就是被嵌套結(jié)構(gòu)體中尺寸最大的基礎(chǔ)類(lèi)型數(shù)據(jù)成員尺寸的倍數(shù)孟害。嵌套結(jié)構(gòu)體的尺寸則是所有被嵌套中的以及自身中的最大基礎(chǔ)類(lèi)型數(shù)據(jù)成員尺寸的倍數(shù)拒炎。

按照上述的規(guī)則,就可以得出上面示例結(jié)構(gòu)體在64位系統(tǒng)下的尺寸了:

64位結(jié)構(gòu)體的內(nèi)存布局

在上面的布局圖中可以看出:

  1. sex數(shù)據(jù)成員是bool型纹坐,它占用1個(gè)字節(jié)的內(nèi)存枝冀,而且是結(jié)構(gòu)體中的第一個(gè)數(shù)據(jù)成員舞丛,第一個(gè)數(shù)據(jù)成員的偏移位置總是從0開(kāi)始(0是任何數(shù)據(jù)類(lèi)型尺寸的倍數(shù))耘子。
  2. age數(shù)據(jù)成員是short int,它占用2個(gè)字節(jié)的內(nèi)存球切,它的偏移位置是2(2是2的倍數(shù))谷誓。同時(shí)我們看到在第一個(gè)數(shù)據(jù)成員和第二個(gè)數(shù)據(jù)成員之間留下了一個(gè)字節(jié)的空隙,我們稱之為padding吨凑。
  3. address數(shù)據(jù)成員是void *, 它占用8個(gè)字節(jié)的內(nèi)存捍歪,它的偏移位置是8(8是8的倍數(shù))。這個(gè)數(shù)據(jù)成員為了對(duì)齊留出了4個(gè)字節(jié)的padding空隙鸵钝。
  4. grade數(shù)據(jù)成員是float, 它占用4個(gè)字節(jié)的內(nèi)存糙臼,它的偏移量是16(16是4的倍數(shù))。這個(gè)成員沒(méi)有留下padding恩商。
  5. name數(shù)據(jù)成員是char[9]变逃,它占用9個(gè)字節(jié),它的偏移位置是20(20是1的倍數(shù))怠堪。它也沒(méi)有留下padding揽乱。
  6. 整個(gè)結(jié)構(gòu)體中最大數(shù)據(jù)成員的尺寸是void*,它占用8個(gè)字節(jié)的內(nèi)存粟矿,因此結(jié)構(gòu)體的尺寸是8的倍數(shù)也就是32個(gè)字節(jié)凰棉。同時(shí)看到在尾部留下了3個(gè)字節(jié)的padding。

從上面的例子可以看出因?yàn)樾枰獙?duì)齊陌粹,結(jié)構(gòu)體中的數(shù)據(jù)成員并不一定是連續(xù)保存的撒犀,而是有可能會(huì)存在一些padding空隙。 這也引出了另外一個(gè)問(wèn)題就是: 當(dāng)我們?cè)诙x結(jié)構(gòu)體時(shí)如果數(shù)據(jù)成員的定義順序安排的不合理就有可能會(huì)導(dǎo)致多余內(nèi)存空間的占用和浪費(fèi)掏秩。 為了達(dá)到最佳內(nèi)存空間占用绘证,可以將上述結(jié)構(gòu)體中數(shù)據(jù)成員的定義順序進(jìn)行調(diào)整如下:

struct Student {
  bool sex;
  char  name[9];
  short int age;
  float grade;
  char *address;
};

就可以得出優(yōu)化后的內(nèi)存布局:

位置調(diào)整后的

那么如何才能得到最優(yōu)的數(shù)據(jù)成員布局順序呢?一個(gè)建議就是:按基礎(chǔ)數(shù)據(jù)類(lèi)型的尺寸從小到大的順序進(jìn)行排列哗讥。

??OC類(lèi)中屬性的定義順序會(huì)引發(fā)內(nèi)存占用的差異嗎嚷那?這個(gè)問(wèn)題留在后面詳細(xì)說(shuō)明。

最后再來(lái)看看結(jié)構(gòu)體有嵌套的情況下尺寸的計(jì)算規(guī)則杆煞,以下面的結(jié)構(gòu)體定義為例:

struct A {
    int a1;
    char a2;
};
struct B {
    char b1;
    struct A b2;
};

結(jié)構(gòu)體A的尺寸在64位系統(tǒng)下占用8個(gè)字節(jié)魏宽,那么結(jié)構(gòu)體B的尺寸以及b2的偏移又是多少呢腐泻?

根據(jù)前面的嵌套規(guī)則定義可以得出: 所有結(jié)構(gòu)體中最大的基礎(chǔ)數(shù)據(jù)類(lèi)型是A中的int a1 ,它占用了4個(gè)字節(jié)队询。因此得出B的尺寸是12派桩,而b2的偏移則是int長(zhǎng)度的倍數(shù),這里應(yīng)該是4蚌斩。

結(jié)構(gòu)體中的位域

結(jié)構(gòu)體中除了可以定義基本數(shù)據(jù)類(lèi)型外铆惑,還可以使用位域來(lái)構(gòu)建數(shù)據(jù)成員,也就是說(shuō)某個(gè)數(shù)據(jù)成員可能只占用結(jié)構(gòu)體中某幾個(gè)bit位的存儲(chǔ)空間送膳。結(jié)構(gòu)體中定義位域的目的主要是為了節(jié)省內(nèi)存空間员魏。假如某個(gè)結(jié)構(gòu)體中有8個(gè)BOOL類(lèi)型的數(shù)據(jù)成員用來(lái)描述8種狀態(tài)。那么我們需要定義8個(gè)BOOL類(lèi)型的數(shù)據(jù)成員叠聋,這樣這個(gè)結(jié)構(gòu)體實(shí)例就占用了8個(gè)字節(jié)的內(nèi)存空間撕阎,而如果我們使用位域來(lái)定義的話則可以用一個(gè)字節(jié)的內(nèi)存空間就可以表述出來(lái)。定義位域的格式如下:

struct Test {
  int a:1;   //冒號(hào)后面指定數(shù)據(jù)成員占用的bit位的位數(shù)碌补。
  int b:2;
};

您也可以參考這篇文章:https://www.cnblogs.com/zzy-frisrtblog/p/6198088.html 有對(duì)位域的詳細(xì)介紹虏束。

在使用位域時(shí)需要注意兩點(diǎn):

  1. 數(shù)據(jù)成員的值不能超過(guò)定義的bit位數(shù),否則就有可能出現(xiàn)覆蓋其他數(shù)據(jù)成員的情況厦章。
  2. 位域數(shù)據(jù)成員不能跨越兩個(gè)數(shù)據(jù)類(lèi)型镇匀。

使用位域結(jié)構(gòu)的一個(gè)經(jīng)典應(yīng)用就是用它來(lái)定義CPU指令。下面是用位域結(jié)構(gòu)體來(lái)定義一條arm64的add加法指令:

//定義add立即數(shù)指令結(jié)構(gòu)
struct arm64_add_immediate {
    uint32_t Rd:5;  //目標(biāo)
    uint32_t Rn:5;
    uint32_t imm12:12;
    uint32_t shift:2;  //00
    uint32_t opS:7; //0010001
    uint32_t sf:1;  //1
};

變長(zhǎng)結(jié)構(gòu)體

在通信領(lǐng)域最常見(jiàn)的就是報(bào)文傳輸了袜啃。一般情況下報(bào)文的結(jié)構(gòu)由報(bào)文頭和報(bào)文體組成汗侵。報(bào)文頭的結(jié)構(gòu)通常是固定的而且具有特定的格式,而報(bào)文體則通常是長(zhǎng)度是可變的一串?dāng)?shù)據(jù)囊骤。報(bào)文頭結(jié)構(gòu)中會(huì)有一個(gè)數(shù)據(jù)成員來(lái)指定報(bào)文體的長(zhǎng)度晃择,而報(bào)文體則通常是跟在報(bào)文頭后面。
對(duì)于這種報(bào)文頭和報(bào)文體的定義我們?nèi)匀豢梢杂靡粋€(gè)結(jié)構(gòu)體來(lái)進(jìn)行統(tǒng)一描述也物。這時(shí)候稱這種結(jié)構(gòu)體為變長(zhǎng)結(jié)構(gòu)體宫屠。變長(zhǎng)結(jié)構(gòu)體一般定義如下:

struct Test {
    //其他任意字段
    int bodySize;
    unsigned char body[0];
};

可以看到結(jié)構(gòu)體的最后定義的是一個(gè)長(zhǎng)度為0的字節(jié)數(shù)組數(shù)據(jù)成員,同時(shí)還定義了一個(gè)bodySize數(shù)據(jù)成員來(lái)指定body所占用的字節(jié)滑蚯。對(duì)于這種可變長(zhǎng)度的結(jié)構(gòu)體實(shí)例通常按如下方式來(lái)構(gòu)建的:

int bodySize = 100;
//為結(jié)構(gòu)體實(shí)例pTest分配內(nèi)存浪蹂,內(nèi)存的大小為結(jié)構(gòu)體的固定長(zhǎng)度和body中的數(shù)據(jù)長(zhǎng)度。
 struct Test *pTest = (struct Test*) malloc (sizeof( struct Test) + bodySize);
//賦值可變長(zhǎng)度
pTest->bodySize = bodySize;

//我們就可以通訪問(wèn)其他數(shù)據(jù)成員一樣來(lái)訪問(wèn)body數(shù)據(jù)成員了告材。
pTest->body

free(pTest);

定義變長(zhǎng)結(jié)構(gòu)體的規(guī)則要求可變長(zhǎng)部分的數(shù)據(jù)成員必須放到最后位置坤次,同時(shí)結(jié)構(gòu)體中還應(yīng)該有一個(gè)數(shù)據(jù)成員來(lái)指定這個(gè)可變長(zhǎng)度成員的所占用的內(nèi)存字節(jié)數(shù)。

結(jié)構(gòu)體在跨平臺(tái)通信中的限制

當(dāng)我們用結(jié)構(gòu)體來(lái)描述通信的數(shù)據(jù)包信息時(shí)斥赋,就可能會(huì)因?yàn)椴煌僮飨到y(tǒng)中字長(zhǎng)的差異或者CPU體系結(jié)構(gòu)體的差異而導(dǎo)致發(fā)送方和接收方無(wú)法匹配而出現(xiàn)異常缰猴。

出現(xiàn)這種問(wèn)題的原因之一就是不同平臺(tái)對(duì)數(shù)據(jù)類(lèi)型的定義是不一樣的
,比如int和long這兩種類(lèi)型是平臺(tái)相關(guān)的類(lèi)型疤剑。因此當(dāng)我們?cè)陂_(kāi)發(fā)跨平臺(tái)通信的應(yīng)用時(shí)就不能使用平臺(tái)相關(guān)的基本數(shù)據(jù)類(lèi)型作為結(jié)構(gòu)體的數(shù)據(jù)成員滑绒,而應(yīng)該明確的指定固定寬度的類(lèi)型以及平臺(tái)無(wú)關(guān)的類(lèi)型來(lái)定義數(shù)據(jù)成員篇亭。

除了數(shù)據(jù)類(lèi)型的約束外晤揣,還有就是對(duì)齊的問(wèn)題逝薪。就如上面介紹的對(duì)齊規(guī)則俏讹,因?yàn)椴煌到y(tǒng)或者編譯器的對(duì)齊規(guī)則不一致,就會(huì)導(dǎo)致當(dāng)我們將結(jié)構(gòu)體序列化進(jìn)行傳輸時(shí)出現(xiàn)異常纵势。因此最佳的實(shí)踐是將結(jié)構(gòu)體中的padding進(jìn)行統(tǒng)一的去除踱阿。這需要在結(jié)構(gòu)體定義中加入如下:

//告訴編譯器保存當(dāng)前的對(duì)齊方式,并將對(duì)齊方式設(shè)置為1字節(jié)
#pragma  pack(push,1)
struct Student {
  bool sex;
  short int age;
  char *address;
  float grade;
  char  name[9];
};
//告訴編譯器恢復(fù)保存的對(duì)齊方式
#pragma pack(pop)           

上述的編譯指令#pragma pack钦铁,可以用來(lái)設(shè)置和恢復(fù)一個(gè)結(jié)構(gòu)體成員的對(duì)齊方式软舌。通過(guò)上述的編譯指令設(shè)置后最終的Student結(jié)構(gòu)體的數(shù)據(jù)成員中將不會(huì)再出現(xiàn)padding空間了。結(jié)構(gòu)體的尺寸就等于所有數(shù)據(jù)成員的尺寸之和了育瓜。

除此之外葫隙,不同的CPU在處理整數(shù)的字節(jié)序上也有差異栽烂,有的是Big Endian有的是Little Endian的躏仇。因此如果結(jié)構(gòu)體中定義有整數(shù)數(shù)據(jù)成員時(shí),也會(huì)出現(xiàn)因?yàn)殡p方字節(jié)序不一致而出現(xiàn)異常腺办。因此在通信時(shí)如果結(jié)構(gòu)體中有整數(shù)數(shù)據(jù)類(lèi)型焰手,一般情況下我們都會(huì)約定為某種統(tǒng)一的字節(jié)序進(jìn)行處理(最常見(jiàn)的就是約定為Big Endian來(lái)處理)。

正是因?yàn)樯鲜龅目偪傁拗苹澈恚虼艘话阄覀冊(cè)趥鬏敂?shù)據(jù)時(shí)很少直接對(duì)結(jié)構(gòu)體進(jìn)行序列化和反序列化處理书妻。而是借助一些平臺(tái)無(wú)關(guān)的數(shù)據(jù)組織格式來(lái)進(jìn)行傳輸,比如JSON躬拢、XML躲履、PB、ASN等等聊闯。當(dāng)然如果通信的雙方都是用C/C++語(yǔ)言來(lái)編寫(xiě)的那么序列化和反序列化效率最高的還是結(jié)構(gòu)體!!

OC類(lèi)的數(shù)據(jù)成員和尺寸

OC類(lèi)的屬性

無(wú)論是結(jié)構(gòu)體還是類(lèi)其實(shí)都是一些數(shù)據(jù)的集合的聲明和描述工猜,OC類(lèi)也是如此。只不過(guò)在OC類(lèi)中除了聲明數(shù)據(jù)成員外菱蔬,還可以定義方法篷帅。當(dāng)然方法本身是不會(huì)占用對(duì)象的存儲(chǔ)空間的。

在OC類(lèi)中聲明的實(shí)體屬性最終會(huì)轉(zhuǎn)化為數(shù)據(jù)成員拴泌。每個(gè)OC類(lèi)中還會(huì)有一個(gè)隱式的數(shù)據(jù)成員isa魏身,這是一個(gè)指針類(lèi)型的數(shù)據(jù)成員,并且是作為類(lèi)的第一個(gè)數(shù)據(jù)成員被定義蚪腐。 因此下面的OC類(lèi)定義:

@interface Student
  @property short int age;
  @property NSString *address;
  @property float grade;
  @property BOOL sex;
@end

如果轉(zhuǎn)化為結(jié)構(gòu)體的話就會(huì)變成:

struct Student {
  void *isa;
  BOOL _sex;
  short int _age;
  float  _grade;
  NSString *_address;
};

從上面的定義中可以看出箭昵,除了會(huì)多出一個(gè)isa數(shù)據(jù)成員外,數(shù)據(jù)成員的順序也發(fā)生了變化回季,它不再是按OC中定義的屬性順序進(jìn)行排列了家制。編譯器會(huì)自動(dòng)優(yōu)化OC類(lèi)中屬性的排列順序掉房, 也就是說(shuō):
OC類(lèi)中定義的屬性順序會(huì)在編譯時(shí)進(jìn)行優(yōu)化調(diào)整,其調(diào)整的規(guī)則就是先按數(shù)據(jù)類(lèi)型的尺寸從小到大進(jìn)行排列慰丛,相同尺寸的數(shù)據(jù)成員則按字母順序進(jìn)行排列卓囚。

因此我們?cè)诙xOC類(lèi)時(shí)不需要考慮屬性的定義順序,系統(tǒng)會(huì)優(yōu)化這些順序以便達(dá)到最小的內(nèi)存占用诅病。

最后再來(lái)說(shuō)說(shuō)OC類(lèi)實(shí)例對(duì)象的內(nèi)存占用問(wèn)題哪亿。OC類(lèi)的對(duì)象內(nèi)存尺寸占用按如下規(guī)則進(jìn)行計(jì)算:

  1. 64位系統(tǒng)中是所有數(shù)據(jù)成員的總和并且是8的倍數(shù),32位系統(tǒng)中是所有數(shù)據(jù)成員的總和并且是4的倍數(shù)贤笆。
  2. 最小為16個(gè)字節(jié)蝇棉。
OC類(lèi)的內(nèi)部數(shù)據(jù)成員

OC類(lèi)中定義的實(shí)例屬性系統(tǒng)在編譯時(shí)會(huì)默認(rèn)轉(zhuǎn)化為一個(gè)帶下劃線的數(shù)據(jù)成員,屬性數(shù)據(jù)成員的內(nèi)存排列順序會(huì)被優(yōu)化處理芥永。在實(shí)際中我們還可以在OC類(lèi)中直接定義內(nèi)部的數(shù)據(jù)成員篡殷,比如下面的形式:

@interface Student
  @property NSString *address;
  @property BOOL sex;
@end

@implementation Student {
   //內(nèi)部的數(shù)據(jù)成員
    BOOL a[7];
    NSString  *b;
}
@end

上面的實(shí)現(xiàn)中定義了兩個(gè)內(nèi)部數(shù)據(jù)成員a,b。當(dāng)出現(xiàn)這種情況時(shí)編譯器不會(huì)對(duì)這些內(nèi)部數(shù)據(jù)成員的順序進(jìn)行優(yōu)化埋涧,而是按定義的順序在內(nèi)存中進(jìn)行排列板辽,并且是優(yōu)先于屬性數(shù)據(jù)成員進(jìn)行排列。因此上面的例子最終的內(nèi)存布局結(jié)構(gòu)為:

struct Student {
  void *isa;
  BOOL a[7];
  NSString *b;
  BOOL _sex;
  NSString *_address;
};

因此個(gè)人不建議在OC類(lèi)中定義內(nèi)部數(shù)據(jù)成員棘催,因?yàn)樗鼤?huì)影響最終的對(duì)象內(nèi)存占用情況劲弦。如果實(shí)在是要定義的話就需要考慮這些內(nèi)部數(shù)據(jù)成員的定義順序以便達(dá)到最佳的內(nèi)存占用布局來(lái)減少對(duì)象內(nèi)存實(shí)例的占用。就以上面的代碼為例醇坝,在64位系統(tǒng)下的最佳定義順序應(yīng)該如下:

@interface Student
  @property NSString *address;
  @property BOOL sex;
@end

@implementation Student {
   //內(nèi)部的數(shù)據(jù)成員
   NSString  *b;
   BOOL a[7];
}
@end

結(jié)構(gòu)體中的OC對(duì)象數(shù)據(jù)成員

OC語(yǔ)言中的對(duì)象基本是基于堆內(nèi)存來(lái)構(gòu)造的邑跪,因此我們所訪問(wèn)和操作的對(duì)象其實(shí)是一個(gè)指針。在MRC時(shí)代這個(gè)指針對(duì)象是由程序員負(fù)責(zé)其生命周期的控制呼猪,到了ARC時(shí)代OC對(duì)象的生命周期控制被編譯器托管画畅。

C語(yǔ)言的結(jié)構(gòu)體對(duì)象沒(méi)有所謂的構(gòu)造和析構(gòu)的概念,所以結(jié)構(gòu)體中的數(shù)據(jù)成員的生命周期必須由程序員來(lái)控制宋距。在當(dāng)前的Xcode編譯器中可以支持將一個(gè)OC對(duì)象定義為一個(gè)結(jié)構(gòu)體的數(shù)據(jù)成員轴踱。為了解決結(jié)構(gòu)體中OC對(duì)象數(shù)據(jù)成員的生命周期問(wèn)題。編譯器會(huì)為每個(gè)包含了OC對(duì)象數(shù)據(jù)成員的結(jié)構(gòu)體自動(dòng)生成一個(gè)隱式的構(gòu)造函數(shù)和隱式的析構(gòu)函數(shù)乡革。每當(dāng)一個(gè)結(jié)構(gòu)體對(duì)象實(shí)例被創(chuàng)建時(shí)系統(tǒng)自動(dòng)會(huì)調(diào)用這個(gè)結(jié)構(gòu)體的隱式構(gòu)造函數(shù)寇僧,隱式構(gòu)造函數(shù)的實(shí)現(xiàn)也很簡(jiǎn)單,就是將結(jié)構(gòu)體中的所有數(shù)據(jù)成員的值清零處理沸版。而每當(dāng)一個(gè)結(jié)構(gòu)體對(duì)象實(shí)例被銷(xiāo)毀時(shí)則會(huì)自動(dòng)調(diào)用隱式的析構(gòu)函數(shù)嘁傀,隱式的析構(gòu)函數(shù)的內(nèi)部實(shí)現(xiàn)是會(huì)將其中的OC對(duì)象數(shù)據(jù)成員置為nil來(lái)減少對(duì)象的引用計(jì)數(shù)。

需要明確的是結(jié)構(gòu)體對(duì)象的構(gòu)造和析構(gòu)調(diào)用只會(huì)發(fā)生在棧內(nèi)存中創(chuàng)建的結(jié)構(gòu)體實(shí)例中视粮。而通過(guò)堆內(nèi)存構(gòu)造的結(jié)構(gòu)體對(duì)象是不會(huì)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的细办。比如下面的代碼:

struct A {
      NSString *a1;
      int a2;
};
 
void main() {

   //當(dāng)函數(shù)結(jié)束后將會(huì)調(diào)用結(jié)構(gòu)體A的默認(rèn)析構(gòu)函數(shù),析構(gòu)函數(shù)會(huì)將a1的引用計(jì)數(shù)減1,是的a1所指的對(duì)象會(huì)在合適的時(shí)機(jī)被釋放笑撞。
   struct A  a;
   a.a1 =  @"Hello world!";
   a.a2 = 10;

  struct A *pA = (struct A *)malloc(sizeof(struct A));
  pA->a1 = @"Hello, world!";
  pA->a2 = 20;

//pA在銷(xiāo)毀時(shí)并不會(huì)調(diào)用析構(gòu)函數(shù)岛啸,這樣就使得a1所指向的OC對(duì)象不會(huì)被釋放,從而導(dǎo)致內(nèi)存泄露的發(fā)生茴肥。
//除非我們?cè)阡N(xiāo)毀pA前坚踩,手動(dòng)調(diào)用pA->a1 = nil;  來(lái)減少引用計(jì)數(shù)。
 free(pA);
}

因此如果我們?cè)诮Y(jié)構(gòu)體中定義OC對(duì)象數(shù)據(jù)成員時(shí)有如下的使用限制:

  1. 結(jié)構(gòu)體對(duì)象的實(shí)例只能在棧內(nèi)存中建立瓤狐,而不能在堆內(nèi)存中建立瞬铸。
  2. 結(jié)構(gòu)體對(duì)象不能以值的形式進(jìn)行函數(shù)參數(shù)的傳遞以及作為函數(shù)的返回。
  3. 結(jié)構(gòu)體對(duì)象是可以以指針的形式作為參數(shù)傳遞础锐。
  4. 如果我們?cè)诙阎薪⒘艘粋€(gè)結(jié)構(gòu)體實(shí)例對(duì)象嗓节,那么請(qǐng)?jiān)阡N(xiāo)毀結(jié)構(gòu)體內(nèi)存之前,先手動(dòng)將所有OC數(shù)據(jù)成員置為nil皆警。

C++類(lèi)中的OC對(duì)象數(shù)據(jù)成員

C++類(lèi)中可以將一個(gè)OC對(duì)象聲明為其數(shù)據(jù)成員拦宣。與結(jié)構(gòu)體不同的是C++類(lèi)中如果有OC對(duì)象數(shù)據(jù)成員時(shí),總是會(huì)在構(gòu)造函數(shù)中將OC對(duì)象數(shù)據(jù)成員值設(shè)置為nil信姓, 同時(shí)會(huì)在析構(gòu)函數(shù)中再次將OC對(duì)象數(shù)據(jù)成員設(shè)為nil并減少引用計(jì)數(shù)鸵隧。 并且無(wú)論你是否重寫(xiě)了構(gòu)造函數(shù)和析構(gòu)函數(shù),上述的兩個(gè)行為都會(huì)被插入到構(gòu)造和析構(gòu)代碼中财破。因此在C++類(lèi)中可以放心的使用OC對(duì)象數(shù)據(jù)成員掰派。


要了解更多的東西請(qǐng)關(guān)注我的:【Github】从诲、【掘金】左痢、【簡(jiǎn)書(shū)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市系洛,隨后出現(xiàn)的幾起案子俊性,更是在濱河造成了極大的恐慌,老刑警劉巖描扯,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件定页,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绽诚,警方通過(guò)查閱死者的電腦和手機(jī)典徊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)恩够,“玉大人卒落,你說(shuō)我怎么就攤上這事》渫埃” “怎么了儡毕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)扑媚。 經(jīng)常有香客問(wèn)我腰湾,道長(zhǎng)雷恃,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任费坊,我火速辦了婚禮倒槐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘附井。我一直安慰自己导犹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布羡忘。 她就那樣靜靜地躺著谎痢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卷雕。 梳的紋絲不亂的頭發(fā)上节猿,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音漫雕,去河邊找鬼滨嘱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛浸间,可吹牛的內(nèi)容都是我干的太雨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼魁蒜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼囊扳!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起兜看,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤锥咸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后细移,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搏予,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年弧轧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雪侥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡精绎,死狀恐怖速缨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捺典,我是刑警寧澤鸟廓,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響引谜,放射性物質(zhì)發(fā)生泄漏牍陌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一员咽、第九天 我趴在偏房一處隱蔽的房頂上張望毒涧。 院中可真熱鬧,春花似錦贝室、人聲如沸契讲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捡偏。三九已至,卻和暖如春峡迷,著一層夾襖步出監(jiān)牢的瞬間银伟,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工绘搞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留彤避,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓夯辖,卻偏偏與公主長(zhǎng)得像琉预,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蒿褂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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

  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用圆米,...
    LZM輪回閱讀 3,314評(píng)論 0 6
  • “ 別猶豫了谴供,如果不合適就分手吧,你總不能把最好的年紀(jì)浪費(fèi)在別人的另一半身上齿坷。這個(gè)世界上有更好的路值得你去走桂肌,有更...
    雜食人間世閱讀 298評(píng)論 0 0
  • (這篇文章來(lái)自10年前的北安,那樣柔軟永淌,那樣欣喜崎场,所以今天看來(lái)有一點(diǎn)點(diǎn)難過(guò)) 始終覺(jué)得詩(shī)歌中的愛(ài)情是四季分明的。 ...
    瞳言勿記閱讀 371評(píng)論 0 0
  • 天空湛藍(lán) 海水也因此一片蔚藍(lán)色 不遠(yuǎn)處的藍(lán)色海面上矗立著一座絕美的蒼翠山峰 它就是嶗山遂蛀。 是青島谭跨。 上海可沒(méi)有 我...
    楊彬_41a0閱讀 456評(píng)論 0 0