iOS寶典--不斷更新中

category 和 extension 的區別

-分類有名字,類擴展沒有分類名字,是一種特殊的分類

-分類只能擴展方法(屬性僅僅是聲明,并沒真正實現),類擴展可以擴展屬性、成員變量和方法

define 和 const常量有什么區別?

-define在預處理階段進行替換,const常量在編譯階段使用

-宏不做類型檢查,僅僅進行替換,const常量有數據類型,會執行類型檢查

-define不能調試,const常量可以調試

-define定義的常量在替換后運行過程中會不斷地占用內存,而const定義的常量存儲在數據段只有一份copy,效率更高

-define可以定義一些簡單的函數,const不可以

block和weak修飾符的區別?

__block不管是ARC還是MRC模式下都可以使用,可以修飾對象,也可以修飾基本數據類型

__weak只能在ARC模式下使用,只能修飾對象(NSString),不能修飾基本數據類型

block修飾的對象可以在block中被重新賦值,weak修飾的對象不可以

static關鍵字的作用

函數(方法)體內 static 變量的作用范圍為該函數體,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;

在模塊內的 static 全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;

在模塊內的 static 函數只可被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明 它的模塊內;

在類中的 static 成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;

在類中的 static 成員函數屬于整個類所擁有,這個函數不接收 this 指針,因而只能訪問類的static 成員變量

堆和棧的區別

-從管理方式來講

對于棧來講,是由編譯器自動管理,無需我們手工控制;

對于堆來說,釋放工作由程序員控制,容易產生內存泄露(memory leak)

-從申請大小大小方面講

棧空間比較小

堆控件比較大

-從數據存儲方面來講

棧空間中一般存儲基本類型,對象的地址

堆空間一般存放對象本身,block的copy等

Objective-C使用什么機制管理對象內存?

MRC 手動引用計數

ARC 自動引用計數,現在通常ARC

通過 retainCount 的機制來決定對象是否需要釋放。 每次 runloop 的時候,都會檢查對象的 retainCount,如果retainCount 為 0,說明該對象沒有地方需要繼續使用了,可以釋放掉了

ARC通過什么方式幫助開發者管理內存?

通過編譯器在編譯的時候,插入類似內存管理的代碼

ARC是為了解決什么問題誕生的?

-首先解釋ARC: automatic reference counting自動引用計數

-了解MRC的缺點

在MRC時代當我們要釋放一個堆內存時,首先要確定指向這個堆空間的指針都被release了

釋放指針指向的堆空間,首先要確定哪些指針指向同一個堆,這些指針只能釋放一次(MRC下即誰創建,誰釋放,避免重復釋放)

模塊化操作時,對象可能被多個模塊創建和使用,不能確定最后由誰去釋放

多線程操作時,不確定哪個線程最后使用完畢

綜上所述,MRC有諸多缺點,很容易造成內存泄露和壞內存的問題,這時蘋果為盡量解決這個問題,從而誕生了ARC

ARC下還會存在內存泄露嗎?

-循環引用會導致內存泄露

-Objective-C對象與CoreFoundation對象進行橋接的時候如果管理不當也會造成內存泄露

-CoreFoundation中的對象不受ARC管理,需要開發者手動釋放

什么情況使用weak關鍵字,相比assign有什么不同?

-首先明白什么情況使用weak關鍵字?

在ARC中,在有可能出現循環引用的時候,往往要通過讓其中一端使用weak來解決,比如:delegate代理屬性,代理屬性也可使用assign

自身已經對它進行一次強引用,沒有必要再強引用一次,此時也會使用weak,自定義IBOutlet控件屬性一般也使用weak;當然,也可以使用strong,但是建議使用weak

- weak 和 assign的不同點

weak策略在屬性所指的對象遭到摧毀時,系統會將weak修飾的屬性對象的指針指向nil,在OC給nil發消息是不會有什么問題的;如果使用assign策略在屬性所指的對象遭到摧毀時,屬性對象指針還指向原來的對象,由于對象已經被銷毀,這時候就產生了野指針,如果這時候在給此對象發送消息,很容造成程序奔潰

- assigin 可以用于修飾非OC對象,而weak必須用于OC對象

@property 的本質是什么?

@property其實就是在編譯階段由編譯器自動幫我們生成ivar成員變量,getter方法,setter方法

ivar、getter、setter是如何生成并添加到這個類中的?

使用“自動合成”( autosynthesis)

這個過程由編譯器在編譯階段執行自動合成,所以編輯器里看不到這些“合成方法”(synthesized method)的源代碼

除了生成getter、setter方法之外,編譯器還要自動向類中添加成員變量(在屬性名前面加下劃線,以此作為實例變量的名字)

為了搞清屬性是怎么實現的,反編譯相關的代碼,他大致生成了五個東西

// 該屬性的“偏移量” (offset),這個偏移量是“硬編碼” (hardcode),表示該變量距離存放對象的內存區域的起始地址有多遠OBJC_IVAR_$類名$屬性名稱// 方法對應的實現函數setter與getter// 成員變量列表ivar_list// 方法列表method_list// 屬性列表prop_list

每次增加一個屬性,系統都會在ivar_list中添加一個成員變量的描述

在method_list中增加setter與getter方法的描述

在prop_list中增加一個屬性的描述

計算該屬性在對象中的偏移量

然后給出setter與getter方法對應的實現,在setter方法中從偏移量的位置開始賦值,在getter方法中從偏移量開始取值,為了能夠讀取正確字節數,系統對象偏移量的指針類型進行了類型強轉

@protocol 和 category 中如何使用 @property

在protocol中使用property只會生成setter和getter方法聲明,我們使用屬性的目的,是希望遵守我協議的對象能實現該屬性

category 使用 @property也是只會生成setter和getter方法聲明,如果我們真的需要給category增加屬性的實現,需要借助于運行時的兩個函數

objc_setAssociatedObject

objc_getAssociatedObject

@property后面可以有哪些修飾符?

原子性---nonatomic特質

如果不寫默認情況為atomic(系統會自動加上同步鎖,影響性能)

在iOS開發中盡量指定為nonatomic,這樣有助于提高程序的性能

讀/寫權限---readwrite(讀寫)、readooly (只讀)

內存管理語義---assign、strong、 weak、unsafe_unretained、copy

方法名---getter=、setter=

@property(nonatomic, getter=isOn)BOOLon;// setter=這種不常用,也**不推薦**使用。故不在這里給出寫法

不常用的:nonnull,null_resettable,nullable

使用atomic一定是線程安全的嗎?

不是,atomic的本意是指屬性的存取方法是線程安全的,并不保證整個對象是線程安全的。

舉例:聲明一個NSMutableArray的原子屬性stuff,此時self.stuff 和self.stuff = othersulf都是線程安全的。但是,使用[self.stuff objectAtIndex:index]就不是線程安全的,需要用互斥鎖來保證線程安全性

@synthesize 和 @dynamic分別有什么作用

@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。如果@synthesize和@dynamic都沒寫,那么默認的就是@syntheszie var = _var;

@synthesize的語義是如果你沒有手動實現setter方法和getter方法,那么編譯器會自動為你加上這兩個方法

@dynamic告訴編譯器:屬性的setter與getter方法由用戶自己實現,不自動生成(當然對于readonly的屬性只需提供getter即可)

假如一個屬性被聲明為@dynamic var,然后你沒有提供@setter方法和@getter方法,編譯的時候沒問題,但是當程序運行到instance.var = someVar,由于缺setter方法會導致程序崩潰;或者當運行到 someVar = instance.var時,由于缺getter方法同樣會導致崩潰。編譯時沒問題,運行時才執行相應的方法,這就是所謂的動態綁定

ARC下,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些?

基本數據:atomic,readwrite,assign

普通的OC對象:atomic,readwrite,strong

@synthesize合成實例變量的規則是什么?假如property名為foo,存在一個名為_foo的實例變量,那么還會自動合成新變量么?

先回答第二個問題:不會

@synthesize合成成員變量的規則,有以下幾點:

如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量

如果這個成員已經存在了就不再生成了

如果指定@synthesize foo;就會生成一個名稱為foo的成員變量,也就是說:會自動生成一個屬性同名的成員變量

@interfaceXMGPerson:NSObject@property(nonatomic,assign)intage;@end@implementationXMGPerson// 不加這語句默認生成的成員變量名為_age// 如果加上這一句就會生成一個跟屬性名同名的成員變量@synthesizeage;@end

如果是 @synthesize foo = _foo; 就不會生成成員變量了

在有了自動合成屬性實例變量之后,@synthesize還有哪些使用場景?

首先的搞清楚什么情況下不會autosynthesis(自動合成)

同時重寫了setter和getter時

重寫了只讀屬性的getter時

使用了@dynamic時

在 @protocol 中定義的所有屬性

在 category 中定義的所有屬性

重載的屬性,當你在子類中重載了父類中的屬性,必須使用@synthesize來手動合成ivar

應用場景

當你同時重寫了setter和getter時,系統就不會生成ivar)。這時候有兩種選擇

手動創建ivar

使用@synthesize foo = _foo;,關聯@property與ivar

可以用來修改成員變量名,一般不建議這么做,建議使用系統自動生成的成員變量

怎么用 copy 關鍵字?

NSString、NSArray、NSDictionary等等經常使用copy關鍵字,是因為他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,為確保對象中的屬性值不會無意間變動,應該在設置新屬性值時拷貝一份,保護其封裝性

block也經常使用copy關鍵字

block 使用 copy 是從 MRC 遺留下來的“傳統”,在 MRC 中,方法內部的 block 是在棧區的,使用 copy 可以把它放到堆區.

在ARC中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但是建議寫上copy,因為這樣顯示告知調用者“編譯器會自動對 block 進行了 copy 操作”

用@property聲明的NSString(或NSArray,NSDictionary)經常使用copy關鍵字,為什么?如果改用strong關鍵字,可能造成什么問題?

因為父類指針可以指向子類對象,使用copy的目的是為了讓本對象的屬性不受外界影響,使用copy無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本.

如果我們使用是strong,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性.

復制詳解

淺復制(shallow copy):在淺復制操作時,對于被復制對象的每一層都是指針復制。

深復制(one-level-deepcopy):在深復制操作時,對于被復制對象,至少有一層是深復制。

完全復制(real-deepcopy):在完全復制操作時,對于被復制對象的每一層都是對象復制。

非集合類對象的copy與mutableCopy

[不可變對象copy]// 淺復制[不可變對象 mutableCopy]//深復制[可變對象copy]//深復制[可變對象 mutableCopy]//深復制

集合類對象的copy與mutableCopy

[不可變對象copy]// 淺復制[不可變對象 mutableCopy]//單層深復制[可變對象copy]//單層深復制[可變對象 mutableCopy]//單層深復制

這里需要注意的是集合對象的內容復制僅限于對象本身,對象元素仍然是指針復制

這個寫法會出什么問題: @property (copy) NSMutableArray *array;

因為copy策略拷貝出來的是一個不可變對象,然而卻把它當成可變對象使用,很容易造成程序奔潰

這里還有一個問題,該屬性使用了同步鎖,會在創建時生成一些額外的代碼用于幫助編寫多線程程序,這會帶來性能問題,通過聲明nonatomic可以節省這些雖然很小但是不必要額外開銷,在iOS開發中應該使用nonatomic替代atomic

如何讓自定義類可以用 copy 修飾符?如何重寫帶 copy 關鍵字的 setter?

若想令自己所寫的對象具有拷貝功能,則需實現NSCopying協議。如果自定義的對象分為可變版本與不可變版本,那么就要同時實現NSCopyiog與NSMutableCopying協議,不過一般沒什么必要,實現NSCopying協議就夠了

// 實現不可變版本拷貝- (id)copyWithZone:(NSZone *)zone;// 實現可變版本拷貝- (id)mutableCopyWithZone:(NSZone *)zone;// 重寫帶 copy 關鍵字的 setter- (void)setName:(NSString*)name{? ? _name = [namecopy];}

+(void)load; +(void)initialize;有什么用處?

+(void)load;

當類對象被引入項目時, runtime 會向每一個類對象發送 load 消息

load 方法會在每一個類甚至分類被引入時僅調用一次,調用的順序:父類優先于子類, 子類優先于分類

由于 load 方法會在類被import 時調用一次,而這時往往是改變類的行為的最佳時機,在這里可以使用例如method swizlling 來修改原有的方法

load 方法不會被類自動繼承

+(void)initialize;

也是在第一次使用這個類的時候會調用這個方法,也就是說 initialize也是懶加載

總結:

在Objective-C中,runtime會自動調用每個類的這兩個方法

+load會在類初始加載時調用

+initialize會在第一次調用類的類方法或實例方法之前被調用

這兩個方法是可選的,且只有在實現了它們時才會被調用

兩者的共同點:兩個方法都只會被調用一次

Foundation對象與Core Foundation對象有什么區別

Foundation框架是使用OC實現的,Core Foundation是使用C實現的

Foundation對象 和 Core Foundation對象間的轉換:俗稱橋接

ARC環境橋接關鍵字:

// 可用于Foundation對象 和 Core Foundation對象間的轉換__bridge// 用于Foundation對象 轉成 Core Foundation對象__bridge_retained// Core Foundation對象 轉成 Foundation對象__bridge_transfer

Foundation對象 轉成 Core Foundation對象

使用__bridge橋接

如果使用__bridge橋接,它僅僅是將strOC的地址給了strC, 并沒有轉移對象的所有權,也就是說, 如果使用__bridge橋接, 那么如果strOC釋放了,strC也不能用了

注意:在ARC條件下,如果是使用__bridge橋接,那么strC可以不用主動釋放, 因為ARC會自動管理strOC和strC

NSString*strOC1 = [NSStringstringWithFormat:@"abcdefg"];CFStringRef strC1 = (__bridge CFStringRef)strOC1;NSLog(@"%@ %@", strOC1, strC1);

使用__bridge_retained橋接

如果使用__bridge_retained橋接,它會將對象的所有權轉移給strC, 也就是說,即便strOC被釋放了, strC也可以使用

注意:在ARC條件下,如果是使用__bridge_retained橋接,那么strC必須自己手動釋放,因為橋接的時候已經將對象的所有權轉移給了strC,而C語言的東西不是不歸ARC管理的

NSString*strOC2 = [NSStringstringWithFormat:@"abcdefg"];//? ? CFStringRef strC2 = (__bridge_retained CFStringRef)strOC2;CFStringRef strC2 = CFBridgingRetain(strOC2);// 這一句, 就等同于上一句CFRelease(strC2);

Core Foundation對象 轉成 Foundation對象

使用__bridge橋接

如果使用__bridge橋接,它僅僅是將strC的地址給了strOC, 并沒有轉移對象的所有權

也就是說如果使用__bridge橋接,那么如果strC釋放了,strOC也不能用了

CFStringRef strC3 = CFStringCreateWithCString(CFAllocatorGetDefault(),"12345678", kCFStringEncodingASCII);NSString*strOC3 = (__bridgeNSString*)strC3;CFRelease(strC3);

使用__bridge_transfer橋接

如果使用__bridge_transfer橋接,它會將對象的所有權轉移給strOC, 也就是說,即便strC被釋放了, strOC也可以使用

如果使用__bridge_transfer橋接, 他會自動釋放strC, 也就是以后我們不用手動釋放strC

CFStringRef strC4 = CFStringCreateWithCString(CFAllocatorGetDefault(),"12345678", kCFStringEncodingASCII);//? ? NSString *strOC = (__bridge_transfer NSString *)strC;NSString*strOC4 = CFBridgingRelease(strC4);// 這一句, 就等同于上一句

MRC環境:直接強轉

-(void)bridgeInMRC{// 將Foundation對象轉換為Core Foundation對象,直接強制類型轉換即可NSString*strOC1 = [NSStringstringWithFormat:@"xxxxxx"];? CFStringRef strC1 = (CFStringRef)strOC1;NSLog(@"%@ %@", strOC1, strC1);? [strOC1 release];? CFRelease(strC1);// 將Core Foundation對象轉換為Foundation對象,直接強制類型轉換即可CFStringRef strC2 = CFStringCreateWithCString(CFAllocatorGetDefault(),"12345678", kCFStringEncodingASCII);NSString*strOC2 = (NSString*)strC2;NSLog(@"%@ %@", strOC2, strC2);? [strOC2 release];? CFRelease(strC2);}

addObserver:forKeyPath:options:context:各個參數的作用分別是什么,observer中需要實現哪個方法才能獲得KVO回調?

/**

1. self.person:要監聽的對象

2. 參數說明

1> 觀察者,負責處理監聽事件的對象

2> 要監聽的屬性

3> 觀察的選項(觀察新、舊值,也可以都觀察)

4> 上下文,用于傳遞數據,可以利用上下文區分不同的監聽

*/[self.personaddObserver:selfforKeyPath:@"name"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Person Name"];/**

*? 當監控的某個屬性的值改變了就會調用

*

*? @param keyPath 監聽的屬性名

*? @param object? 屬性所屬的對象

*? @param change? 屬性的修改情況(屬性原來的值、屬性最新的值)

*? @param context 傳遞的上下文數據,與監聽的時候傳遞的一致,可以利用上下文區分不同的監聽

*/- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context{NSLog(@"%@對象的%@屬性改變了:%@", object, keyPath, change);}

KVO內部實現原理

KVO是基于runtime機制實現的

當某個類的屬性對象第一次被觀察時,系統就會在運行期動態地創建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的setter 方法。派生類在被重寫的setter方法內實現真正的通知機制

如果原類為Person,那么生成的派生類名為NSKVONotifying_Person

每個類對象中都有一個isa指針指向當前類,當一個類對象的第一次被觀察,那么系統會偷偷將isa指針指向動態生成的派生類,從而在給被監控屬性賦值時執行的是派生類的setter方法

鍵值觀察通知依賴于NSObject 的兩個方法: willChangeValueForKey: 和 didChangevlueForKey:;在一個被觀察屬性發生改變之前, willChangeValueForKey: 一定會被調用,這就 會記錄舊的值。而當改變發生后,didChangeValueForKey: 會被調用,繼而 observeValueForKey:ofObject:change:context: 也會被調用。

補充:KVO的這套實現機制中蘋果還偷偷重寫了class方法,讓我們誤認為還是使用的當前類,從而達到隱藏生成的派生類

如何手動觸發一個value的KVO

自動觸發的場景:在注冊KVO之前設置一個初始值,注冊之后,設置一個不一樣的值,就可以觸發了

想知道如何手動觸發,必須知道自動觸發 KVO 的原理,見上面的描述

手動觸發演示

@property(nonatomic,strong)NSDate*now;- (void)viewDidLoad{? ? [superviewDidLoad];// “手動觸發self.now的KVO”,必寫。[selfwillChangeValueForKey:@"now"];// “手動觸發self.now的KVO”,必寫。[selfdidChangeValueForKey:@"now"];}

若一個類有實例變量NSString *_foo,調用setValue:forKey:時,是以foo還是_foo作為key?

都可以

KVC的keyPath中的集合運算符如何使用?

必須用在集合對象上或普通對象的集合屬性上

簡單集合運算符有@avg, @count , @max , @min ,@sum

格式 @"@sum.age" 或 @"集合屬性.@max.age"???

KVC和KVO的keyPath一定是屬性么?

可以是成員變量

如何關閉默認的KVO的默認實現,并進入自定義的KVO實現?

如何自己動手實現 KVO

apple用什么方式實現對一個對象的KVO?

此題就是問KVO的實現原理

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

推薦閱讀更多精彩內容

  • category 和 extension 的區別 分類有名字,類擴展沒有分類名字,是一種特殊的分類 分類只能擴展方...
    Andyzhao閱讀 6,867評論 1 58
  • 一、category 和 extension 的區別?(分類和擴展的區別) 1,分類有名字,類擴展沒有名字,是一種...
    閃電迷閱讀 738評論 0 3
  • category 和 extension 的區別? category :分類有名字,類擴展沒i有分類名字,是一種特...
    JonesCxy閱讀 299評論 0 1
  • category 和 extension 的區別? category :分類有名字,類擴展沒i有分類名字,是一種特...
    WSGNSLog閱讀 185評論 0 1
  • “今天晚上吃什么。” “不吃,我減肥。” “吃不吃燒烤。” “吃吃吃!” 坐辦公室的妹子都有一顆減肥的心,試圖減過...
    梅子卷閱讀 285評論 0 2