OC-基礎(chǔ)總結(jié)(二)

OC基礎(chǔ)總結(jié)

重新回過頭看這些基礎(chǔ)知識,對許多知識點都有新的認識,擁有堅實的基礎(chǔ)才能更快的成長。

OC內(nèi)存管理 - 基礎(chǔ)與MRC

內(nèi)存管理概述

  1. 內(nèi)存管理
    內(nèi)存的作用:存儲數(shù)據(jù)。
    1). 如何將數(shù)據(jù)存儲到內(nèi)存之中。
    聲明1個變量,然后將數(shù)據(jù)存儲進去。
    2). 當數(shù)據(jù)不再被使用的時候,占用的內(nèi)存空間如何被釋放。
  2. 內(nèi)存中的五大區(qū)域

    棧: 局部變量,當局部變量的作用域被執(zhí)行完畢之后,這個局部變量就會被系統(tǒng)立即回收。
    堆: OC對象,使用C函數(shù)申請的空間。需要我們自己進行內(nèi)存管理
    BSS段: 未初始化的全局變量、靜態(tài)變量。一旦初始化就回收,并轉(zhuǎn)存到數(shù)據(jù)段之中。
    數(shù)據(jù)段: 已經(jīng)初始化的全局變量、靜態(tài)變量。直到程序結(jié)束的時候才會被回收。
    代碼段: 代碼,程序結(jié)束的時候系統(tǒng)會自動回收存儲在代碼段中的數(shù)據(jù)。

棧、BSS段、數(shù)據(jù)段、代碼段存儲在它們中的數(shù)據(jù)的回收,是由系統(tǒng)自動完成的,不需要我們干預(yù)。

  1. 分配在堆區(qū)中的OC對象,是肯定需要被回收的。
    iPhone 內(nèi)存機制,會在占用內(nèi)存40M及45M時警告,達到120M時就會直接閃退。
    而存儲在堆中的OC對象,系統(tǒng)不會自動回收,直到程序結(jié)束的時候才會被回收。

  2. 內(nèi)存管理的范圍:
    只需要管理存儲在堆中的OC對象的回收,其他區(qū)域中的數(shù)據(jù)的回收是系統(tǒng)自動管理的,不需要我們進行管理。

  3. 對象應(yīng)該什么時候被回收?
    當有人使用這個對象的時候,這個對象就千萬不能回收。只有在沒有任何人使用這個對象的時候,才可以回收。

  4. 引用計數(shù)器
    1). 每1個對象都有1個屬性,叫做retainCount引用計數(shù)器,類型是unsigned long占據(jù)8個字節(jié)。
    引用計數(shù)器的作用: 用來記錄當前這個對象有多少個人在使用它,默認情況下,創(chuàng)建1個對象出來,這個對象的引用計數(shù)器的默認值是1。
    2). 當多1個人使用這個對象的時候,應(yīng)該先讓這個對象的引用計數(shù)器的值+1代表這個對象多1個人使用。
    3). 當這個對象少1個人使用的時候,應(yīng)該先讓這個對象的引用計數(shù)器的值-1代表這個對象少1個人使用。
    4). 當這個對象的引用計數(shù)器變?yōu)?的時候,代表這個對象無人使用,這個時候系統(tǒng)就會自動回收這個對象。

  5. 如何操作引用計數(shù)器.
    1). 為對象發(fā)送1條retain消息,對象的引用計數(shù)器就會加1,當多1個人使用對象的時候才發(fā)。
    2). 為對象發(fā)送1條release消息,對象的引用計數(shù)器就會減1,當少1個人使用對象的時候才發(fā)。
    3). 為對象發(fā)送1條retainCount消息,就可以取到對象的引用計數(shù)器的值。
    4). 對象的引用計數(shù)器變?yōu)?的時候,對象就會被系統(tǒng)立即回收,在對象被回收的時候,會自動調(diào)用對象的dealloc方法。

  6. 內(nèi)存管理的分類
    MRC: Manual Reference Counting 手動引用計數(shù)-手動內(nèi)存管理-當多1個人使用對象的時候,要求程序員手動的發(fā)送retain消息,少1個人使用的時候程序員手動的發(fā)送relase消息。
    ARC: Automatic Reference Counting 自動引用計數(shù)-自動內(nèi)存管理-系統(tǒng)自動的在合適的地方發(fā)送retain relase消息。

  7. MRC
    1). 新創(chuàng)建1個對象,這個對象的引用計數(shù)器的值默認是1。
    2). 當對象的引用計數(shù)器變?yōu)?的時候,對象就會被系統(tǒng)立即回收并自動調(diào)用dealloc方法。
    3). 為對象發(fā)送retain消息,對象的引用計數(shù)器就會+1。
    4). 為對象發(fā)送release消息,并不是回收對象,而是讓對象的引用計數(shù)器-1
    當對象的引用計數(shù)器的值變?yōu)?的時候,對象才會被系統(tǒng)立即回收。
    MRC中重寫dealloc方法的規(guī)范:
    必須要調(diào)用父類的dealloc方法,并且要放在最后一句代碼。

  8. 內(nèi)存管理的重點及原則
    1). 有對象的創(chuàng)建,就要匹配1個release。
    2). retain的次數(shù)和release的次數(shù)要匹配。
    3). 誰用誰retain,誰不用誰release,誰負責retain誰就負責relase。
    4). 只有在多1個人用的時候才retain,少1個人使用的時候才release。有加就有減,有retain就應(yīng)該匹配1個release一定要平衡。
    5). 在ARC機制下,retain release dealloc這些方法方法無法調(diào)用.

  9. 野指針
    C語言中的野指針: 定義1個指針變量,沒有初始化,這個指針變量的值是1個垃圾值,指向1塊隨機的空間,那么這個指針就叫做野指針。
    OC中的野指針: 指針指向的對象已經(jīng)被回收了,這樣的指針就叫做野指針。

  10. 對象及內(nèi)存回收的本質(zhì)
    申請1個變量,實際上就是向系統(tǒng)申請指定字節(jié)數(shù)的空間,這些空間系統(tǒng)就不會再分配給別人了。當變量被回收的時候,代表變量占用的字節(jié)空間從此以后系統(tǒng)可以分配給別人使用了。但是字節(jié)空間中存儲的數(shù)據(jù)還在。
    所謂的對象的回收,指的是對象占用的空間可以分配給別人。當這個對象占用的空間沒有分配給別人之前 其實對象數(shù)據(jù)還在.

  11. 僵尸對象
    1個已經(jīng)被釋放的對象,但是這個對象所占的空間還沒有分配給別人,這樣的對象叫做僵尸對象。
    我們通過野指針去訪問僵尸對象的時候,如果僵尸對象占用的空間還沒有分配給別人的時候,這時是可以的,而當僵尸對象占用的空間分配給了別人使用的時候,是萬萬不可的。
    因此只要對象成為了僵尸對象,無論如何都不允許訪問了。
    Xcode提供了僵尸對象的實時檢查機制,可以將這個機制打開,打開之后,只要訪問的是僵尸對象,無論空間是否分配就會報錯。

  12. 為什么不默認打開僵尸對象檢測.
    一旦打開僵尸對象檢測那么在每訪問1個對象的時候,都會先檢查這個對象是否為1個僵尸對象。這樣是極其消耗性能的。
    打開僵尸對象檢測:Product -> Scheme -> EditScheme -> Diagnostict -> Zombie Objects

  13. 使用野指針訪問僵尸對象會報錯,如何避免僵尸對象錯誤。
    當1個指針稱為野指針以后,將這個指針的值設(shè)置nil。
    當1個指針的值為nil,通過這個指針去調(diào)用對象的方法(包括使用點語法)的時候,不會報錯,只是沒有任何反應(yīng),但是如果通過直接訪問屬性 -> 就會報錯。

  14. 內(nèi)存泄露
    指的是1個對象沒有被及時的回收,在該回收的時候而沒有被回收,一直駐留在內(nèi)存中,直到程序結(jié)束的時候才回收。
    單個對象的內(nèi)存泄露的情況:
    1). 有對象的創(chuàng)建,而沒有對應(yīng)的relase。
    2). retain的次數(shù)和relase的次數(shù)不匹配。
    3). 在不適當?shù)臅r候,為指針賦值為nil。
    4). 在方法中為傳入的對象進行不適當?shù)膔etain。

  15. 當屬性是1個OC對象的時候 setter方法的寫法
    將傳進來的對象賦值給當前對象的屬性,代表傳入的對象多了1個人使用,所以我們應(yīng)該先為這個傳入的對象發(fā)送1條retain消息再賦值。
    當為對象的這個屬性多次賦值的時候,代表舊對象少1個人用,新對象多1個人使用,應(yīng)該relase舊的 retain新的。
    當當前對象銷毀的時候,代表屬性指向的對象少1個人使用,就應(yīng)該在dealloc中relase。
    代碼寫法:

     - (void)setCar:(Car *)car
     {
         if(_car != car)
         {
            [_car release];
            _car = [car retain];
         }
     }
 
     還要重寫dealloc方法.
     - (void)dealloc
     {
        [_car release];
        [super delloc];
     }

@property

  1. @property 作用
    1). 自動生成私有屬性。
    2). 自動生成這個屬性的getter setter方法的聲明。
    3). 自動生成這個屬性的getter setter方法的實現(xiàn)。
  2. @property參數(shù)
    1). @property可以帶參數(shù)的.
    @property(參數(shù)1,參數(shù)2,參數(shù)3......)數(shù)據(jù)類型 名稱;
    2). 介紹一下@property的四組參數(shù).

與多線程相關(guān)的兩個參數(shù) nonatomic - atomic
與生成的setter方法的實現(xiàn)相關(guān)的參數(shù) assign - retain
與生成只讀、讀寫相關(guān)的參數(shù) readonly - readwrite
是與生成的getter setter方法名字相關(guān)的參數(shù) getter - setter

3). 介紹與多線程相關(guān)的參數(shù).

atomic: 默認值,如果寫atomic,這個時候生成的setter方法的代碼就會被加上一把線程安全鎖。
特點: 安全、但是效率低下。
nonatomic: 如果寫nonatomic這個時候生成的setter方法的代碼就不會加線程安全鎖。
特點: 不安全,但是效率高。

4). 與生成的setter方法的實現(xiàn)相關(guān)的參數(shù)。

assign: 默認值,生成的setter方法的實現(xiàn)就是直接賦值。
retain: 生成的setter方法的實現(xiàn)就是標準的MRC內(nèi)存管理代碼,也就是先判斷新舊對象是否為同1個對象,如果不是 release舊的 retain新的。
當屬性的類型是OC對象類型的時候,那么就使用retain。
當屬性的類型是非OC對象的時候,使用assign。
千萬注意:
retain參數(shù),只是生成標準的setter方法為標準的MRC內(nèi)存管理代碼,不會自動的再dealloc中生成relase的代碼。所以,還要自己手動的在dealloc中release。

5). 與生成只讀、讀寫的封裝。

readwrite: 默認值,代表同時生成getter setter。
readonly: 只會生成getter,不會生成setter

6). 生成getter、setter方法名稱相關(guān)的參數(shù)。

默認情況下@property生成的getter setter方法的名字都是最標準的名字。同時我們可以通過參數(shù)來指定@property生成的方法的名字。

getter = getter方法名字 用來指定@property生成的getter方法的名字。
setter = setter方法名字 用來指定@property生成的setter方法的名字。注意.setter方法是帶參數(shù)的所以要加1個冒號。
注意:如果使用getter setter修改了生成的方法的名字,在使用點語法的時候,編譯器會轉(zhuǎn)換為調(diào)用修改后的名字的代碼。

注意:無論什么情況都不要改setter方法的名字,因為默認情況下生成的名字就已經(jīng)是最標準的了。
當屬性的類型是1個BOOL類型的時候,可以修改這個getter的名字以is開頭以提高代碼的閱讀性。

7). 同1組參數(shù)只能使用1個,參數(shù)的順序可以隨意。

@class與#import的區(qū)別

  1. 當兩個類相互包含的時會出現(xiàn)循環(huán)引用的問題,造成無限遞歸,而導(dǎo)致無法編譯通過。
  2. 解決方案:
    其中一邊不要使用#import引入對方的頭文件,而是使用@class 類名;來標注這是1個類,這樣就可以在不引入對方頭文件的情況下,告訴編譯器這是1個類。
    在.m文件中再#import對方的頭文件即可。
  3. 區(qū)別
    1). #import是將指定的文件的內(nèi)容拷貝到寫指令的地方。
    2). @class 并不會拷貝任何內(nèi)容,只是告訴編譯器,這是1個類,這樣編譯器在編譯的時候才可以知道這是1個類。

OC內(nèi)存管理 - ARC與分類

  1. 自動釋放池的原理
    存入到自動釋放池中的對象,在自動釋放池被銷毀的時候,會自動調(diào)用存儲在該自動釋放池中的所有對象的release方法。
    可以解決的問題:
    將創(chuàng)建的對象,存入到自動釋放池之中,就不再需要手動的relase這個對象了,因為池子銷毀的時候,就會自動的調(diào)用池中所有的對象的relase。
    自動釋放池的好處: 將創(chuàng)建的對象存儲到自動釋放池中,不需要再寫release。

  2. 如何創(chuàng)建自動釋放池
    @autoreleasepool{

     }
     //這對大括弧代表這個自動釋放池的范圍。
    
  3. 如何將對象存儲到自動釋放池之中
    在自動釋放池之中調(diào)用對象的autorelease方法,就會將這個對象存入到當前自動釋放池之中。
    //autorealse方法返回的是對象本身。
    @autoreleasepool{
    Person *p1 = [[[Person alloc] init] autorelease];
    }
    當這個自動釋放池執(zhí)行完畢之后,就會立即為這個自動釋放池中的對象發(fā)送1條release消息。

  4. 使用注意
    1). 只有在自動釋放池中調(diào)用了對象的autorelease方法,這個對象才會被存儲到這個自動釋放池之中,如果只是將對象的創(chuàng)建代碼寫在自動釋放之中,而沒有調(diào)用對象的autorelease方法,是不會將這個對象存儲到這個自動釋放池之中的。
    2). 對象的創(chuàng)建可以在自動釋放池的外面,在自動釋放池之中,調(diào)用對象的autorelease方法,就可以將這個對象存儲到這個自動釋放池之中。
    3). autorelease在外面是無法將對象存在自動釋放池之中的,當自動釋放池結(jié)束的時候,僅僅是對存儲在自動釋放池中的對象發(fā)送1條release消息,而不是銷毀對象。
    4). 如果在自動釋放池中,調(diào)用同1個對象的autorelease方法多次,就會將對象存儲多次到自動釋放池之中。在自動釋放池結(jié)束的時候,會為對象發(fā)送多條release消息,那么這個是就會出現(xiàn)僵尸對象錯誤。所以,1個自動釋放池之中,只autorelease1次,只將這個對象放1次,否則就會出現(xiàn)野指針錯誤。
    5). 如果在自動釋放池中,調(diào)用了存儲到自動釋放池中的對象的release方法,在自動釋放池結(jié)束的時候,還會再調(diào)用對象的release方法。這個時候就有可能會造成野指針操作。
    也可以調(diào)用存儲在自動釋放池中的對象的retain方法.
    6). 將對象存儲到自動釋放池,并不會使對象的引用計數(shù)器+1
    所以其好處就是:創(chuàng)建對象將對象存儲在自動釋放池,就不需要在寫個release了。 省略創(chuàng)建對象匹配的那個release
    7). 自動釋放池可以嵌套
    調(diào)用對象的autorelease方法,會將對象加入到當前自動釋放池之中,只有在當前自動釋放池結(jié)束的時候才會像對象發(fā)送release消息。

  5. autorelease的規(guī)范
    使用類方法創(chuàng)建的對象,要求這個對象在方法中就已經(jīng)被autorelease過了,這樣,我們只要在自動釋放池中,調(diào)用類方法來創(chuàng)建對象,那么創(chuàng)建的對象就會被自動的加入到自動釋放池中。
    而使用對象方法不會自動autorelease。

      提供1個類方法來快速的得到1個對象.
      規(guī)范
      a. 這個類方法以類名開頭. 如果沒有參數(shù)就直接是類名 如果有參數(shù)就是 類名WithXX:
      b. 使用類方法得到的對象,要求這個對象就已經(jīng)被autorelease過了. 
      + (instancetype)person
      {
         return [[[self alloc] init] autorelease];
      }
    
      這樣,我們直接調(diào)用類方法.就可以得到1個已經(jīng)被autorelease過的對象.
      @autoreleasepool
      {
          Person *p1 = [Person person];
          //這個p1對象已經(jīng)被autorelase過了.不需要再調(diào)用autorelase
          //這個p1對象就被存儲到當前自動釋放池之中.
      }//當自動釋放池結(jié)束.就會為存儲在其中的p1對象發(fā)送release消息.
    

Apple的框架中的類也是遵守這個規(guī)范的。通過類方法創(chuàng)建的對象都是已經(jīng)被autorelease過的了。
所以,我們也要遵守這個規(guī)范,類方法返回的對象也要被autorealse過。我們凡是創(chuàng)建對象是調(diào)用類方法創(chuàng)建的對象,這個對象已經(jīng)是被autorelease過的。

ARC

  1. ARC - Automatic Reference Counting,自動引用計數(shù),即ARC。系統(tǒng)自動的幫助我們?nèi)ビ嬎銓ο蟮囊糜嫈?shù)器的值。
    在程序中使用ARC非常簡單,只需要像往常那樣編寫代碼,只不過永遠不要寫retain、release、autorelease 永遠不要手動的調(diào)用 dealloc 這是ARC的最基本的原則。
    特別注意的是ARC是編譯器機制,當ARC開啟時,編譯器會自動的在合適的地方插入retain、release、autorelase代碼,自動為對象做引用計數(shù)。
  2. ARC機制下,對象何時被釋放
    本質(zhì): 對象的引用計數(shù)器為0的時候,自動釋放。
    表象: 只要沒有強指針指向這個對象,這個對象就會立即回收。
  3. 強指針與弱指針
    強指針: 默認情況下,聲明1個指針,這個指針就是1個強指針。
    我們也可以使用__strong來顯示的聲明這是1個強指針。
    Person *p1; // 這是1個強指針. 指針默認情況下都是1個強指針。
    __strong Person *p2; // 這也是1個強指針.使用__strong來顯示的聲明強指針。
    弱指針: 使用__weak標識的指針就叫做弱指針。
    無論是強指針還是弱指針,都是指針,都可以用來存儲地址,這1點沒有任何區(qū)別,都可以通過這個指針訪問對象的成員。
    唯一的區(qū)別就是在ARC模式下,他們用來作為回收對象的基準。
    如果1個對象沒有任何強類型的指針指向這個對象的時候,對象就會被立即自動釋放

ARC下的單個對象的內(nèi)存管理

在ARC的機制下: 當1個對象沒有任何的強指針指向它的時候,這個對象就會被立即回收。

1). 當1個對象沒有任何的強指針指向它的時候,這個對象就會被立即回收。

    int main(int argc, const char * argv[])
    {
        @autoreleasepool
        {
           Person *p1 = [Person new];//p1是1個強指針.
           Person *p2 = p1;//p2也是個強指針.p1和p2都指向Person對象.
           //因為我們說過,每1個指針變量默認情況下都是1個強指針變量.
           NSLog(@"------");
        }//當執(zhí)行到這里的時候.p1指針被回收,p2指針也被回收.那么Person對象就沒有任何
        //強指針指向它了. 對象就在這被回收.
        return 0;
    }

2).將所有指向?qū)ο蟮膹娭羔樫x值為nil的時候.對象就會被立即回收.

 int main(int argc, const char * argv[])
 {
     @autoreleasepool
     {
         Person *p1 = [Person new];//p1是1個強指針.
         //因為我們說過,每1個指針變量默認情況下都是1個強指針變量.        
         p1 = nil;//當執(zhí)行到這句話的時候.p1賦值為nil.
         //p1指針不再指向Person對象.
         //Person對象沒有被任何的指針所指向,所以.Person對象在這里被釋放.
         NSLog(@"------");
     }
     return 0;
 } 
 這兩種情況就叫做沒有任何強指針指向?qū)ο?
 1). 指向?qū)ο蟮乃袕娭羔槺换厥盏? 2). 指向?qū)ο蟮乃械膹娭羔樫x值為nil

ARC機制下釋放1個對象的標準是: 沒有任何強指針指向?qū)ο蟮臅r候,對象就會被釋放,如果這個時候有弱指針指向,也會被釋放.

 int main(int argc, const char * argv[])
 {
     @autoreleasepool
     {
         //使用__strong來標識p1指針是強類型的,其實不寫__strong也是強類型的.
         __strong Person *p1 = [[Person alloc] init];
         
         //使用__weak標識指針p2的類型是弱類型指針.
         __weak Person *p2 = p1;
         //這個時候,p2指針和p1指針都指向Person對象.
         
         //這個時候如果設(shè)置p1的值為nil
         p1 = nil;
         //這個時候Person對象只有被1個弱指針p2指向,沒有任何強指針指向
         //所以Person對象在這里被回收.
     }
     return 0;
 }

3). 最重要的1點:不能創(chuàng)建對象用1個弱指針存儲這個對象的指針,這樣的話,剛創(chuàng)建出來的對象,就沒有任何強指針指向,創(chuàng)建出來就會被回收。

 int main(int argc, const char * argv[])
 {
     @autoreleasepool
     {
         //創(chuàng)建1個對象,將這個對象的地址賦值給1個弱指針
         //后果就是創(chuàng)建出來的這個對象沒有被任何強指針指向.
         //剛創(chuàng)建出來就會被釋放.
         __weak Person *p1 = [[Person alloc] init];
         
     }
     return 0;
 }

4). 在ARC機制下,當對象被回收的時候,原來指向這個對象的弱指針會被自動設(shè)置為nil。

 Person *p1 = [Person new];
 __weak Person p2 = p1;
 p1 = nil;
 [p2 sayHi];

ARC機制下的重點

當1個類的屬性是1個OC對象的時候,這個屬性應(yīng)該聲明為強類型的還是弱類型的。很明顯,應(yīng)該聲明為1個強類型的。
使用參數(shù),strong和weak控制@property生成的私有屬性是1個強類型的還是1個弱類型的。

 @property(nonatomic,strong)Car *car;
 代表生成的私有屬性_car 是1個強類型的. 
 @property(nonatomic,weak)Car *car;
 代表生成的私有屬性_car 是1個弱類型的.

如果不寫,默認是strong.

使用建議
1). 在ARC機制下,如果屬性的類型是OC對象類型的,絕大多數(shù)場景下使用strong。
2). 在ARC機制下,如果屬性的類型不是OC對象類型的,使用assign。
3). strong和weak都是應(yīng)用在屬性的類型是OC對象的時候,屬性的類型不是OC對象的時候就使用assign。
4). 在ARC機制下,當兩個對象相互引用的時候,如果兩邊都使用strong 那么就會內(nèi)存泄露。解決方案: 1端使用strong 1端使用weak。
5). 使用命令-fno-objc-arc設(shè)置部分類使用MRC。
6). 可以將整個MRC程序,轉(zhuǎn)換為ARC程序;
Edit -> Convert ->To Objective-C ARC (不建議使用)

分類 - category

將1個類分為多個模塊
使用分類的幾個注意點:

  1. 分類只能增加方法,不能增加屬性

  2. 在分類之中可以寫@property 但是不會自動生成私有屬性,也不會自動生成getter setter的實現(xiàn),只會生成getter setter的聲明。
    所以需要自己寫getter 和 setter的聲明,如果也需要自己定義屬性,這個屬性就必須在本類中。

  3. 在分類的方法實現(xiàn)中不可以直接訪問本類的真私有屬性(定義在本類的@implementation之中),但是可以調(diào)用本類的getter setter來訪問屬性。

  4. 分類中可以存在和本類同名方法的
    當分類中有和本類中同名的方法的時候,優(yōu)先調(diào)用分類的方法,哪怕沒有引入分類的頭文件。
    如果多個分類中有相同的方法,優(yōu)先調(diào)用最后編譯的分類。

  5. 什么時候需要使用分類
    當1個類的方法很多很雜的時候,當1個類很臃腫的時候。那么這個時候我們就可以使用分類,將這個類分為多個模塊,將功能相似的方法寫在同1個模塊之中。

  6. 非正式協(xié)議 - 為系統(tǒng)自帶的類寫分類就叫做非正式協(xié)議。

ARC機制與垃圾回收機制的區(qū)別

垃圾回收機制 - GC: 程序在運行的期間,有1個東西叫做垃圾回收器,不斷的掃描堆中的對象是否無人使用。
ARC: 不是運行時,而在編譯的時候就在合適的地方插入retain 等操作,插入的代碼足以讓對象無人使用的時候,引用計數(shù)器為0,對象被回收。


文中如果有不對的地方歡迎指出。我是xx_cc,一只長大很久但還沒有二夠的家伙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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