成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

速度追求:Objective-C高性能的循環(huán)

開發(fā) 后端
Cocoa編程的一個(gè)通常的任務(wù)是要去循環(huán)遍歷一個(gè)對(duì)象的集合 (例如,一個(gè) NSArray, NSSet 或者是 NSDictionary). 這個(gè)看似簡(jiǎn)單的問題有廣泛數(shù)量的解決方案,它們中的許多不乏有對(duì)性能方面問題的細(xì)微考慮.

Cocoa編程的一個(gè)通常的任務(wù)是要去循環(huán)遍歷一個(gè)對(duì)象的集合 (例如,一個(gè) NSArray, NSSet 或者是 NSDictionary). 這個(gè)看似簡(jiǎn)單的問題有廣泛數(shù)量的解決方案,它們中的許多不乏有對(duì)性能方面問題的細(xì)微考慮.

對(duì)于速度的追求

首先,是一個(gè)免責(zé)聲明: 相比其它問題而言,一個(gè) Objective-C 方法原始的速度是你在編程時(shí)***才需要考慮的問題之一 – 區(qū)別就在于這個(gè)問題夠不上去同其它更加需要重點(diǎn)考慮的問題進(jìn)行比較,比如說代碼的清晰度和可讀性.

但速度的次要性并不妨礙我們?nèi)ダ斫馑? 你應(yīng)該經(jīng)常去了解一下性能方面的考慮將如何對(duì)你正在編寫的代碼產(chǎn)生影響,一邊在極少數(shù)發(fā)生問題的情況下,你會(huì)知道如何下手.

還有,在循環(huán)的場(chǎng)景中,大多數(shù)時(shí)候不管是從可讀性或者是清晰度考慮,你選擇哪種技術(shù)都沒什么關(guān)系的, 所以你還不如選擇速度最快的那一種. 沒有必要選擇編碼速度比要求更慢的。

考慮到這一點(diǎn),就有了如下的選擇:

經(jīng)典的循環(huán)方式

  1. for (NSUInteger i = 0; i < [array count]; i++){  
  2.   id object = array[i];  
  3.   …} 

這是循環(huán)遍歷一個(gè)數(shù)組的一個(gè)簡(jiǎn)單熟悉的方式; 從性能方面考慮它也相當(dāng)?shù)牟顒? 這段代碼***的問題就是循環(huán)每進(jìn)行一次我們都會(huì)調(diào)用數(shù)組的計(jì)數(shù)方法. 數(shù)組的總數(shù)是不會(huì)改變的,因此每次都去調(diào)用一下這種做法是多余的. 像這種代碼一般C編譯器一般都會(huì)優(yōu)化掉, 但是 Objective-C 的動(dòng)態(tài)語言特性意味著對(duì)這個(gè)方法的調(diào)用不會(huì)被自動(dòng)優(yōu)化掉. 因此,為了提升性能,值得我們?cè)谘h(huán)開始之前,將這個(gè)總數(shù)存到一個(gè)變量中,像這樣:

  1. NSUInteger count = [array count];for (NSUInteger i = 0; i < count; i++){  
  2.   id object = array[i];  
  3.   …} 

NSEnumerator

NSEnumerator 是循環(huán)遍歷集合的一種可選方式. 所有的集合都已一個(gè)或者更多個(gè)枚舉方法,每次它們被調(diào)用的時(shí)候都會(huì)返回一個(gè)NSEnumerator實(shí)體. 一個(gè)給定的 NSEnumerator 會(huì)包含一個(gè)指向集合中***個(gè)對(duì)象的指針, 并且會(huì)有一個(gè) nextObject 方法返回當(dāng)前的對(duì)象并對(duì)指針進(jìn)行增長. 你可以重復(fù)調(diào)用它直到它返回nil,這表明已經(jīng)到了集合的末尾了:

  1. id obj = nil;NSEnumerator *enumerator = [array objectEnumerator];while ((obj = [enumerator nextObject]));{  
  2.   …            

NSEnumerator 的性能可以媲美原生的for循環(huán), 但它更加實(shí)用,因?yàn)樗鼘?duì)索引的概念進(jìn)行了抽象,這意味著它應(yīng)用在結(jié)構(gòu)化數(shù)據(jù)上,比如鏈表,或者甚至是無窮序列和數(shù)據(jù)流,這些結(jié)構(gòu)中的數(shù)據(jù)條數(shù)未知或者并沒有被定義.

快速枚舉

快速枚舉是在 Objective-C 2.0 中作為傳統(tǒng)的NSEnumerator的更便利(并且明顯更快速) 的替代方法而引入的. 它并沒有使得枚舉類過時(shí)因?yàn)槠淙匀槐粦?yīng)用于注入反向枚舉, 或者是當(dāng)你需要對(duì)集合進(jìn)行變更操作 (之后會(huì)更多地提到) 這些場(chǎng)景中.
快速枚舉添加了一個(gè)看起來像下面這樣子的新的枚舉方法:

  1. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state   
  2.    objects:(id *)stackbuf count:(NSUInteger)len; 

如果你正在想著“那看起來并不怎么舒服啊!”, 我不會(huì)怪你的. 但是新的方法順便帶來了一種新的循環(huán)語法, for…in 循環(huán). 這是在幕后使用了新的枚舉方法, 并且重要的是在語法和性能上都比使用傳統(tǒng)的for循環(huán)或者 NSEnumerator 方法都更省心了:

  1. for (id object in array){  
  2.   …} 

枚舉塊

隨著塊的誕生,Apple加入第四個(gè)基于塊語法的枚舉機(jī)制. 這無疑比快速枚舉更加的少見, 但是有一個(gè)優(yōu)勢(shì)就是對(duì)象和索引都會(huì)返回, 而其他的枚舉方法只會(huì)返回對(duì)象.

枚舉塊的另外一個(gè)關(guān)鍵特性就是可選擇型的并發(fā)枚舉 (在幾個(gè)并發(fā)的線程中枚舉對(duì)象). 這不是經(jīng)常有用,取決于你在自己的循環(huán)中具體要做些什么, 但是在你正有許多工作要做,并且你并不怎么關(guān)心枚舉順序的場(chǎng)景下,它在多核處理器上可能會(huì)產(chǎn)生顯著的性能提高 (現(xiàn)在所有的 Mac和iOS設(shè)備都已經(jīng)有了多核處理器).

基準(zhǔn)測(cè)試

那么這些方法疊加起來會(huì)如何呢, 性能會(huì)更加的好么? 這里有一個(gè)簡(jiǎn)單的基準(zhǔn)測(cè)試命令行應(yīng)用,比較了使用多種不同方法枚舉一個(gè)數(shù)據(jù)的性能. 我們已經(jīng)在 ARC 關(guān)閉的情況下運(yùn)行了它,以排除任何干擾最終結(jié)果的隱藏在幕后的保留或者排除處理. 由于是運(yùn)行在一個(gè)很快的 Mac 機(jī)上面, 所有這些方法運(yùn)行極快以至于我們實(shí)際上不得不使用一個(gè)存有10,000,000 (一千萬) 對(duì)象的數(shù)組來測(cè)量結(jié)果. 如果你決定在一個(gè) iPhone 進(jìn)行測(cè)試, 最明智的做法是使用一個(gè)小得多的數(shù)量!

為了編譯這段代碼:

  • 把代碼保存在一個(gè)文件中,命名為 benchmark.m

  • 在終端中編譯應(yīng)用程序:
    clang -framework Foundation benchmark.m -o benchmark

  • 運(yùn)行程序: ./benchmark

  1. #import <Foundation/Foundation.h> int main(int argc, const char * argv[]){  
  2.   @autoreleasepool  {  
  3.     static const NSUInteger arrayItems = 10000000;  
  4.      NSMutableArray *array = [NSMutableArray arrayWithCapacity:arrayItems];    for (int i = 0; i < arrayItems; i++) [array addObject:@(i)];  
  5.     array = [array copy];  
  6.     
  7.     CFTimeInterval start = CFAbsoluteTimeGetCurrent();  
  8.      // Naive for loop  
  9.     for (NSUInteger i = 0; i < [array count]; i++)  
  10.     {  
  11.       id object = array[i];    }   
  12.     CFTimeInterval forLoop = CFAbsoluteTimeGetCurrent();  
  13.     NSLog(@"For loop: %g", forLoop - start);  
  14.      // Optimized for loop  
  15.     NSUInteger count = [array count];    for (NSUInteger i = 0; i <  count; i++)  
  16.     {  
  17.       id object = array[i];    }   
  18.     CFTimeInterval forLoopWithCountVar = CFAbsoluteTimeGetCurrent();  
  19.     NSLog(@"Optimized for loop: %g", forLoopWithCountVar - forLoop);  
  20.      // NSEnumerator  
  21.     id obj = nil;    NSEnumerator *enumerator = [array objectEnumerator];    while ((obj = [enumerator nextObject]))  
  22.     {     }   
  23.     CFTimeInterval enumeratorLoop = CFAbsoluteTimeGetCurrent();  
  24.     NSLog(@"Enumerator: %g", enumeratorLoop - forLoopWithCountVar);  
  25.      // Fast enumeration  
  26.     for (id object in array)  
  27.     {     }   
  28.     CFTimeInterval forInLoop = CFAbsoluteTimeGetCurrent();  
  29.     NSLog(@"For…in loop: %g", forInLoop - enumeratorLoop);  
  30.      // Block enumeration  
  31.     [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {     }];  
  32.     
  33.     CFTimeInterval enumerationBlock = CFAbsoluteTimeGetCurrent();  
  34.     NSLog(@"Enumeration block: %g", enumerationBlock - forInLoop);  
  35.      // Concurrent enumeration  
  36.     [array enumerateObjectsWithOptions:NSEnumerationConcurrent   
  37.       usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {     }];  
  38.     
  39.     CFTimeInterval concurrentEnumerationBlock = CFAbsoluteTimeGetCurrent();  
  40.     NSLog(@"Concurrent enumeration block: %g",   
  41.       concurrentEnumerationBlock - enumerationBlock);  }  
  42.   return 0;} 

下面展示出了結(jié)果:

  1. $ For loop: 0.119066  
  2. $ Optimized for loop: 0.092441  
  3. $ Enumerator: 0.123687  
  4. $ For…in loop: 0.049296  
  5. $ Enumeration block: 0.295039  
  6. $ Concurrent enumeration block: 0.199684 

忽略掉時(shí)間的具體長短. 我們感興趣的是它們同其它方法比較的相對(duì)大小. 如果我們按順序排列它們,快的放前面,我會(huì)得到了下面的結(jié)果:

  1. For…in循環(huán) – 最快.

  2. 對(duì)for循環(huán)的優(yōu)化 – 比 for…in 慢兩倍.

  3. 沒有優(yōu)化的for循環(huán) – 比 for…in 慢2.5倍.

  4. Enumerator – 大約同沒有優(yōu)化的循環(huán)相同.

  5. 并發(fā)的枚舉塊 – 比 for…in 大約慢6倍.

  6. 枚舉塊 – 比 for…in 幾乎慢6倍.

For…in 是勝出者. 顯然他們將其稱為快速枚舉是有原因的! 并發(fā)枚舉看起來是比單線程的快一點(diǎn)點(diǎn), 但是你沒必要對(duì)其做更多的解讀: 我們這里是在枚舉一個(gè)非常非常大型的對(duì)象數(shù)組,而對(duì)于小一些的數(shù)據(jù)并發(fā)執(zhí)行的開銷遠(yuǎn)多于其帶來的好處.

并發(fā)執(zhí)行的主要是在當(dāng)你的循環(huán)需要大量的執(zhí)行時(shí)間時(shí)有優(yōu)勢(shì). 如果你在自己的循環(huán)中有許多東西要運(yùn)行,那就考慮試下并行枚舉,在你不關(guān)心枚舉順序的前提下 (但是請(qǐng)用行動(dòng)的去權(quán)衡一下它是否變得更快樂,不要空手去揣度).

#p#

其它集合類型Other Collection Types

那么其它的結(jié)合類型怎么樣呢, 比如 NSSet 和 NSDictionary? NSSet 是無序的, 因此沒有按索引去取對(duì)象的概念.我們也可以進(jìn)行一下基準(zhǔn)測(cè)試:

  1. $ Enumerator: 0.421863  
  2. $ For…in loop: 0.095401  
  3. $ Enumeration block: 0.302784  
  4. $ Concurrent enumeration block: 0.390825 

結(jié)果同 NSArray 一致; for…in 再一次勝出了. NSDictionary怎么樣了? NSDictionary 有一點(diǎn)不同因?yàn)槲覀兺瑫r(shí)又一個(gè)鍵和值對(duì)象需要迭代. 在一個(gè)字典中單獨(dú)迭代鍵或者值是可以的, 但典型的情況下我們兩者都需要. 這里我們有一段適配于操作NSDictionary的基準(zhǔn)測(cè)試代碼:

  1. #import <Foundation/Foundation.h> int main(int argc, const char * argv[]){  
  2.   @autoreleasepool  {  
  3.     static const NSUInteger dictItems = 10000;  
  4.      NSMutableDictionary *dictionary =   
  5.       [NSMutableDictionary dictionaryWithCapacity:dictItems];    for (int i = 0; i < dictItems; i++) dictionary[@(i)] = @(i);  
  6.     dictionary = [dictionary copy];  
  7.     
  8.     CFTimeInterval start = CFAbsoluteTimeGetCurrent();  
  9.      // Naive for loop  
  10.     for (NSUInteger i = 0; i < [dictionary count]; i++)  
  11.     {  
  12.       id key = [dictionary allKeys][i];      id object = dictionary[key];    }   
  13.     CFTimeInterval forLoop = CFAbsoluteTimeGetCurrent();  
  14.     NSLog(@"For loop: %g", forLoop - start);  
  15.      // Optimized for loop  
  16.     NSUInteger count = [dictionary count];    NSArray *keys = [dictionary allKeys];    for (NSUInteger i = 0; i <  count; i++)  
  17.     {  
  18.       id key = keys[i];      id object = dictionary[key];    }   
  19.     CFTimeInterval forLoopWithCountVar = CFAbsoluteTimeGetCurrent();  
  20.     NSLog(@"Optimized for loop: %g", forLoopWithCountVar - forLoop);  
  21.      // NSEnumerator  
  22.     id key = nil;    NSEnumerator *enumerator = [dictionary keyEnumerator];    while ((key = [enumerator nextObject]))  
  23.     {  
  24.       id object = dictionary[key];    }   
  25.     CFTimeInterval enumeratorLoop = CFAbsoluteTimeGetCurrent();  
  26.     NSLog(@"Enumerator: %g", enumeratorLoop - forLoopWithCountVar);  
  27.      // Fast enumeration  
  28.     for (id key in dictionary)  
  29.     {  
  30.       id object = dictionary[key];    }   
  31.     CFTimeInterval forInLoop = CFAbsoluteTimeGetCurrent();  
  32.     NSLog(@"For…in loop: %g", forInLoop - enumeratorLoop);  
  33.      // Block enumeration  
  34.     [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {     }];  
  35.     
  36.     CFTimeInterval enumerationBlock = CFAbsoluteTimeGetCurrent();  
  37.     NSLog(@"Enumeration block: %g", enumerationBlock - forInLoop);  
  38.      // Concurrent enumeration  
  39.     [dictionary enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent   
  40.       usingBlock:^(id key, id obj, BOOL *stop) {     }];  
  41.     
  42.     CFTimeInterval concurrentEnumerationBlock = CFAbsoluteTimeGetCurrent();  
  43.     NSLog(@"Concurrent enumeration block: %g",   
  44.       concurrentEnumerationBlock - enumerationBlock);  }  
  45.   return 0;}  

NSDictionary 填充起來比 NSArray 或者 NSSet 慢得多, 因此我們把數(shù)據(jù)條數(shù)減少到了10,000 (一萬) 以避免機(jī)器鎖住. 因而你應(yīng)該忽略結(jié)果怎么會(huì)比那些 NSArray 低那么多,因?yàn)槲覀兪褂玫氖歉賹?duì)象的 1000 次循環(huán):

  1. $ For loop: 2.25899  
  2. $ Optimized for loop: 0.00273103  
  3. $ Enumerator: 0.00496799  
  4. $ For…in loop: 0.001041  
  5. $ Enumeration block: 0.000607967  
  6. $ Concurrent enumeration block: 0.000748038 

沒有優(yōu)化過的循環(huán)再這里慢得很壯觀,因?yàn)槊恳淮挝覀兌紡?fù)制了鍵數(shù)組. 通過把鍵數(shù)組和總數(shù)存到變量中,我們獲得了更快的速度. 查找對(duì)象的消耗現(xiàn)在主宰了其它的因素,因此使用一個(gè)for循環(huán), NSEnumerator 或者for…in 差別很小. 但是對(duì)于枚舉塊方法而言,它在一個(gè)方法中把鍵和值都返回了,所以現(xiàn)在變成了最快的選擇。

反轉(zhuǎn)齒輪

基于我們所見,如果所有其它的因素都一樣的話,在循環(huán)遍歷數(shù)組時(shí)你應(yīng)該嘗試去使用for...in循環(huán), 而遍歷字典時(shí),則應(yīng)該選擇枚舉塊. 也有一些場(chǎng)景下這樣的做法并不可能行得通,比如我們需要回頭來進(jìn)行枚舉,或者當(dāng)我們?cè)诒闅v時(shí)想要變更集合的情況.
為了回過頭來枚舉一個(gè)數(shù)據(jù),我們可以調(diào)用reverseObjectEnumerator方法來獲得一個(gè)NSEnumerator 以從尾至頭遍歷數(shù)組. NSEnumerator, 就像是 NSArray 它自己, 支持快速的枚舉協(xié)議. 那就意味著我們?nèi)匀豢梢栽谶@種方式下使用 for…in, 而無速度和簡(jiǎn)潔方面的損失:

  1. for (id object in [array reverseObjectEnumerator])   
  2. {  
  3. …  } 

(除非你異想天開, NSSet 或者 NSDictionary 是沒有等效的方法的, 而反向枚舉一個(gè) NSSet 或者NSDictionary無論如何都沒啥意義, 因?yàn)殒I是無序的.)

如果你想使用枚舉塊的話, NSEnumerationReverse你可以試試, 像這樣:

  1. [array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {  
  2.   …  }]; 

變更Mutation

應(yīng)用同樣的循環(huán)技術(shù)到變更中的集合上是可能的; 其性能也大致相同. 然而當(dāng)你嘗試在循環(huán)數(shù)組或者字典的時(shí)候修改它們,你可能經(jīng)常會(huì)面臨這樣的異常:

  1. '*** Collection XYZ was mutated while being enumerated.' 

就像我們優(yōu)化了的for循環(huán), 所有這些循環(huán)技術(shù)的性能取決于事先把數(shù)據(jù)總數(shù)存下來,這意味著如果你開始在循環(huán)中間加入或者去掉一個(gè)數(shù)據(jù)時(shí),這個(gè)數(shù)據(jù)就不正確了. 但是在循環(huán)進(jìn)行中加入,替換或者移除一條數(shù)據(jù)時(shí)經(jīng)常想要做的事情. 那么什么才是這個(gè)問題的解決之道呢?

我們經(jīng)典的for循環(huán)可以工作得很好,因?yàn)樗灰蕾囉隈v留的總數(shù)常量; 我們只需要記得,如果我們添加或者移除了一條數(shù)據(jù),就要增加或者減小索引. 但我們已經(jīng)了解到for循環(huán)并不是一種速度快的解決方案. 我們優(yōu)化過的for循環(huán)則是一個(gè)合理的選擇, 只要我們記得按需遞增或者遞減技術(shù)變量,還有索引.

我們?nèi)匀豢梢允褂胒or…in, 但前提是我們首先創(chuàng)建了一個(gè)數(shù)組的拷貝. 這會(huì)起作用的,例如:

  1. for (id object in [array copy])   
  2.  {  
  3.    // Do something that modifies the array, e.g. [array removeObject:object];  
  4.  } 

如果我們對(duì)不同的技術(shù)進(jìn)行基準(zhǔn)測(cè)試(必要時(shí)把復(fù)制數(shù)組的開銷算在內(nèi),以便我們可以對(duì)原來數(shù)組內(nèi)的數(shù)據(jù)進(jìn)行變更), 我們發(fā)現(xiàn)復(fù)制抵消了 for…in 循環(huán)之前所擁有的好處:

  1. $ For loop: 0.111422  
  2. $ Optimized for loop: 0.08967  
  3. $ Enumerator: 0.313182  
  4. $ For…in loop: 0.203722  
  5. $ Enumeration block: 0.436741  
  6. $ Concurrent enumeration block: 0.388509 

在我們遍歷一個(gè)數(shù)組時(shí)修改這個(gè)數(shù)組最快的計(jì)數(shù),似乎是需要使用一個(gè)優(yōu)化了的for循環(huán)的.

對(duì)于一個(gè) NSDictionary, 我們不需要為了使用NSEnumerator 或者快速枚舉而復(fù)制整個(gè)字典; 我們可以只去使用allKeys方法獲取到所有鍵的一個(gè)副本. 這都將能很好的運(yùn)作起來:

  1. // NSEnumerator  
  2.   id key = nil;  NSEnumerator *enumerator = [[items allKeys] objectEnumerator];  while ((key = [enumerator nextObject]))  
  3.   {  
  4.     id object = items[key];    // Do something that modifies the value, e.g. dictionary[key] = newObject;  
  5.   }   // Fast enumeration  
  6.   for (id key in [dictionary allkeys])   
  7.   {  
  8.     id object = items[key];    // Do something that modifies the value, e.g. dictionary[key] = newObject;  
  9.   } 

然而同樣的技術(shù)在使用enumerateKeysAndObjectsUsingBlock方法時(shí)并不能起作用. 如果我們循環(huán)遍歷一個(gè)字典進(jìn)行基準(zhǔn)測(cè)試, 按照需要對(duì)鍵或者對(duì)字典整體創(chuàng)建備份,我們得到了下面的結(jié)果:

  1. $ For loop: 2.24597  
  2. $ Optimized for loop: 0.00282001  
  3. $ Enumerator: 0.00508499  
  4. $ For…in loop: 0.000990987  
  5. $ Enumeration block: 0.00144804  
  6. $ Concurrent enumeration block: 0.00166804 

這里我們可以看到 for…in 循環(huán)是最快的一個(gè). 那是因?yàn)樵趂or...in循環(huán)中根據(jù)鍵取對(duì)象的開銷現(xiàn)在已經(jīng)被在調(diào)用枚舉塊方法之前復(fù)制字典的開銷蓋過去了.

當(dāng)枚舉一個(gè)NSArray的時(shí)候:

  • 使用 for (id object in array) 如果是順序枚舉

  • 使用 for (id object in [array reverseObjectEnumerator]) 如果是倒序枚舉

  • 使用 for (NSInteger i = 0; i < count; i++) 如果你需要知道它的索引值,或者需要改變數(shù)組

  • 嘗試 [array enumerateObjectsWithOptions:usingBlock:] 如果你的代碼受益于并行執(zhí)行

當(dāng)枚舉一個(gè)NSSet的時(shí)候:

  • 使用  for (id object in set) 大多數(shù)時(shí)候

  • 使用 for (id object in [set copy]) 如果你需要修改集合(但是會(huì)很慢)

  • 嘗試 [array enumerateObjectsWithOptions:usingBlock:] 如果你的代碼受益于并行執(zhí)行

當(dāng)枚舉一個(gè)NSDictionary的時(shí)候:

  • 使用  for (id object in set) 大多數(shù)時(shí)候

  • 使用 for (id object in [set copy]) 如果你需要修改詞典

  • 嘗試 [array enumerateObjectsWithOptions:usingBlock:] 如果你的代碼受益于并行執(zhí)行

這些方法可能不是最快的,但他們都是非常清晰易讀的。所以請(qǐng)記住,有時(shí)是在不寫干凈的代碼,和快速的代碼之間做出選擇,你會(huì)發(fā)現(xiàn),你可以在兩個(gè)世界得到***的。

英文原文:Tips for High Performance Collection Looping in Objective-C

譯文鏈接:http://www.oschina.net/translate/high-performance-collection-looping-objective-c

責(zé)任編輯:林師授 來源: 中國開源社區(qū)編譯
相關(guān)推薦

2013-06-20 10:40:32

Objective-C實(shí)現(xiàn)截圖

2013-03-27 12:54:00

iOS開發(fā)Objective-C

2011-05-11 15:58:34

Objective-C

2011-05-11 11:20:26

Objective-C

2011-08-10 18:07:29

Objective-C反射

2014-11-25 10:18:17

Objective-C

2014-07-29 09:44:35

2013-04-11 13:41:30

Objective-CiOS編程

2011-08-03 16:55:05

Objective-C 代理

2011-08-04 09:35:09

Objective-C 編碼規(guī)范

2014-04-30 10:16:04

Objective-CiOS語法

2014-06-25 14:02:59

Objective-CKVO

2012-03-07 13:43:59

Objective-C

2011-07-29 16:16:30

Objective-c block

2011-07-08 13:49:46

Objective-C UUID

2012-06-15 09:47:48

Objective-CCategory

2011-08-17 10:58:59

Objective-C構(gòu)造函數(shù)

2011-05-11 13:54:08

Objective-C

2011-05-11 15:45:50

內(nèi)存管理Objective-C

2011-08-02 13:16:36

Objective-C 語法 函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩在线国产 | 亚洲国产精品久久 | 美女视频一区 | 中文字幕 欧美 日韩 | 久久91| 色小姐综合网 | 精品无码久久久久久国产 | 91一区二区 | 国产精品久久福利 | 黄色毛片黄色毛片 | 人人爽人人爽人人片av | 性做久久久久久免费观看欧美 | 麻豆国产一区二区三区四区 | 国外成人在线视频 | 午夜视频在线 | 91精品久久久久久久久久 | 成人精品视频在线观看 | 日韩在线视频免费观看 | 99精品视频一区二区三区 | 搞黄网站在线观看 | 久久激情视频 | 美女视频网站久久 | 久久精品国产久精国产 | 国产精品免费一区二区三区四区 | 国产伦精品一区二区三区视频金莲 | 国产精品久久影院 | www.狠狠操| 久久一区二区三区电影 | 天天操夜夜操 | 久久99精品久久久久久国产越南 | 久久久成人一区二区免费影院 | 免费亚洲婷婷 | 在线高清免费观看视频 | 日本黄色大片免费 | 久久成人18免费网站 | 97色在线视频| 91在线视频播放 | 成人av鲁丝片一区二区小说 | 国产精久久久久久久妇剪断 | 国产视频二区 | 亚洲黄色成人网 |