NSArray üzerinde yineleme yapmak için standart deyim arıyorum. Kodumun OS X 10.4+ için uygun olması gerekir.
NSArray üzerinde yineleme yapmak için standart deyim arıyorum. Kodumun OS X 10.4+ için uygun olması gerekir.
Yanıtlar:
10.5 + / iOS için genellikle tercih edilen kod.
for (id object in array) {
// do something with object
}
Bu yapı, NSFastEnumeration
protokole uyan bir koleksiyondaki nesneleri numaralandırmak için kullanılır . Bu yaklaşımın bir hız avantajı vardır, çünkü bir tamponda birkaç nesneye (tek bir yöntem çağrısı yoluyla elde edilen) işaretçileri saklar ve işaretçi aritmetiği kullanılarak tamponda ilerleyerek bunlar üzerinden yineler. Bu, döngü boyunca her seferinde çağırmaktan çok daha hızlıdır -objectAtIndex:
.
Bu teknik olarak ise dikkati çekiyor var olabilir kullanmak bir for-bir ile adıma döngü NSEnumerator
buldum ki bu da tehlikeye sokan neredeyse tüm hızlı numaralandırma hız avantajı. Bunun nedeni, varsayılan NSEnumerator
uygulama -countByEnumeratingWithState:objects:count:
yerleri her çağrıda tamponu içinde yalnızca bir nesne.
Bunu radar://6296108
(NSEnumerators'ın hızlı numaralandırması durgun) olarak bildirdim, ancak Düzeltilmeyecek şekilde döndürüldü. Bunun nedeni, hızlı numaralandırmanın bir grup nesneyi önceden getirmesidir ve numaralandırıcıda yalnızca belirli bir noktaya numaralandırmak istiyorsanız (örneğin belirli bir nesne bulunana veya koşul karşılanana kadar) ve ayrıldıktan sonra aynı numaralandırıcıyı kullanın genellikle birkaç nesnenin atlanması söz konusu olabilir.
OS X 10.6 / iOS 4.0 ve üstü için kod yazıyorsanız, dizileri ve diğer koleksiyonları numaralandırmak için blok tabanlı API'leri kullanma seçeneğiniz de vardır:
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// do something with object
}];
Ayrıca seçenekler argümanı olarak -enumerateObjectsWithOptions:usingBlock:
ve geçebilir NSEnumerationConcurrent
ve / veya kullanabilirsiniz NSEnumerationReverse
.
10.5 öncesi için standart deyim bir NSEnumerator
and while döngüsü kullanmaktır, şöyle:
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
}
Basit tutmanızı tavsiye ederim. Kendinizi bir dizi türüne bağlamak esnek değildir ve kullanımdaki hızlı artış, -objectAtIndex:
yine de 10.5+ üzerinde hızlı numaralandırma ile iyileştirme açısından önemsizdir. (Hızlı numaralandırma aslında temeldeki veri yapısı üzerinde işaretçi aritmetiği kullanır ve yöntem çağrısı ek yükünü kaldırır.) Erken optimizasyon asla iyi bir fikir değildir - yine de darboğazınız olmayan bir sorunu çözmek için daha karmaşık bir kodla sonuçlanır.
Kullanırken -objectEnumerator
, kolayca başka bir numaralandırılabilir koleksiyona (bir NSSet
, bir anahtarlar NSDictionary
, vb. Gibi) kolayca geçiş yapabilir veya hatta -reverseObjectEnumerator
bir diziyi geriye doğru numaralandırmak için geçiş yapabilirsiniz; Yineleme kodu bir yöntemdeyse, herhangi bir tanesini bile geçebilirsiniz NSEnumerator
ve kodun yinelediği şeyi umursamaya bile gerek yoktur . Ayrıca, NSEnumerator
(en azından Apple kodu tarafından sağlananlar), daha fazla nesne olduğu sürece numaralandırdığı koleksiyonu korur, bu nedenle otomatik olarak yayımlanan bir nesnenin ne kadar süreceği konusunda endişelenmenize gerek yoktur.
Belki de bir NSEnumerator
(veya hızlı numaralandırma) sizi koruyan en büyük şey, numaralandırma sırasında sizin bilginiz olmadan altınızda değiştirilebilir bir koleksiyon (dizi veya başka türlü) bir değişiklik yapmaktır . Nesneleri dizine göre erişirseniz, hata ayıklamak için korkunç olabilecek garip istisnalar veya tek tek hatalar (genellikle sorun ortaya çıktıktan uzun süre sonra) ile karşılaşabilirsiniz. Standart deyimlerden birini kullanarak numaralandırma "başarısız-hızlı" davranışı vardır, bu nedenle mutasyon meydana geldikten sonra bir sonraki nesneye erişmeye çalıştığınızda sorun (yanlış koddan kaynaklanan) hemen kendini gösterir. Programlar daha karmaşık ve çok iş parçacıklı hale geldikçe veya üçüncü taraf kodunun değiştirebileceği bir şeye bağlı olduğundan, hassas numaralandırma kodu giderek daha sorunlu hale gelir. Kapsülleme ve soyutlama FTW! :-)
for (id object in array)
, dizideki nesnelerin geçerli dizinini de belirlemenin bir yolu mu yoksa ayrı bir sayacın dahil edilmesi gerekiyor mu?
for
for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
OS X 10.4.x ve öncesi için:
int i;
for (i = 0; i < [myArray count]; i++) {
id myArrayElement = [myArray objectAtIndex:i];
...do something useful with myArrayElement
}
OS X 10.5.x (veya iPhone) ve üstü için:
for (id myArrayElement in myArray) {
...do something useful with myArrayElement
}
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
muhtemelen bu yaklaşım için alacağınız en verimli ve özlüdür.
Test ve kaynak kodun sonuçları aşağıdadır (uygulamada yineleme sayısını ayarlayabilirsiniz). Süre milisaniye cinsindendir ve her giriş, testi 5-10 kez çalıştırmanın ortalama sonucudur. Genellikle 2-3 anlamlı basamağa kadar doğru olduğunu gördüm ve bundan sonra her çalışmada değişecektir. Bu,% 1'den daha az bir hata payı verir. Test, ilgilendiğim hedef platform olduğu için bir iPhone 3G'de çalışıyordu.
numberOfItems NSArray (ms) C Array (ms) Ratio
100 0.39 0.0025 156
191 0.61 0.0028 218
3,256 12.5 0.026 481
4,789 16 0.037 432
6,794 21 0.050 420
10,919 36 0.081 444
19,731 64 0.15 427
22,030 75 0.162 463
32,758 109 0.24 454
77,969 258 0.57 453
100,000 390 0.73 534
Cocoa tarafından veri setlerini (NSDictionary, NSArray, NSSet vb.) İşlemek için sağlanan sınıflar, bellek yönetimi, yeniden tahsis vb. Bürokrasisi hakkında endişelenmek zorunda kalmadan, bilgileri yönetmek için çok güzel bir arayüz sağlar. . Ben NSNumbers bir NSArray kullanarak basit iterasyonlar için bir yüzer C Array daha yavaş olacağını söylemek çok açık olduğunu düşünüyorum, bu yüzden bazı testler yapmaya karar verdim ve sonuçlar oldukça şok edici oldu! Bu kadar kötü olmasını beklemiyordum. Not: Bu testler, ilgilendiğim hedef platform olduğu için bir iPhone 3G'de gerçekleştirilir.
Bu testte bir C float * ve NSNumbers NSArray arasında çok basit bir rasgele erişim performansı karşılaştırması yapıyorum
Ben her dizinin içeriğini özetlemek ve mach_absolute_time () kullanarak onları zamanlamak için basit bir döngü oluşturun. NSMutableArray ortalama 400 kat daha uzun sürer !! (yüzde 400 değil, sadece 400 kat daha uzun! bu% 40.000 daha uzun!).
Başlık:
// Array_Speed_TestViewController.h
// Dizi Hız Testi
// Mehmet Akten tarafından 05/02/2009 tarihinde hazırlandı.
// Telif Hakkı MSA Visuals Ltd. 2009. Tüm hakları saklıdır.
#import <UIKit/UIKit.h>
@interface Array_Speed_TestViewController : UIViewController {
int numberOfItems; // number of items in array
float *cArray; // normal c array
NSMutableArray *nsArray; // ns array
double machTimerMillisMult; // multiplier to convert mach_absolute_time() to milliseconds
IBOutlet UISlider *sliderCount;
IBOutlet UILabel *labelCount;
IBOutlet UILabel *labelResults;
}
-(IBAction) doNSArray:(id)sender;
-(IBAction) doCArray:(id)sender;
-(IBAction) sliderChanged:(id)sender;
@end
Uygulama:
// Array_Speed_TestViewController.m
// Dizi Hız Testi
// Mehmet Akten tarafından 05/02/2009 tarihinde hazırlandı.
// Telif Hakkı MSA Visuals Ltd. 2009. Tüm hakları saklıdır.
#import "Array_Speed_TestViewController.h"
#include <mach/mach.h>
#include <mach/mach_time.h>
@implementation Array_Speed_TestViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSLog(@"viewDidLoad");
[super viewDidLoad];
cArray = NULL;
nsArray = NULL;
// read initial slider value setup accordingly
[self sliderChanged:sliderCount];
// get mach timer unit size and calculater millisecond factor
mach_timebase_info_data_t info;
mach_timebase_info(&info);
machTimerMillisMult = (double)info.numer / ((double)info.denom * 1000000.0);
NSLog(@"machTimerMillisMult = %f", machTimerMillisMult);
}
// pass in results of mach_absolute_time()
// this converts to milliseconds and outputs to the label
-(void)displayResult:(uint64_t)duration {
double millis = duration * machTimerMillisMult;
NSLog(@"displayResult: %f milliseconds", millis);
NSString *str = [[NSString alloc] initWithFormat:@"%f milliseconds", millis];
[labelResults setText:str];
[str release];
}
// process using NSArray
-(IBAction) doNSArray:(id)sender {
NSLog(@"doNSArray: %@", sender);
uint64_t startTime = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += [[nsArray objectAtIndex:i] floatValue];
}
[self displayResult:mach_absolute_time() - startTime];
}
// process using C Array
-(IBAction) doCArray:(id)sender {
NSLog(@"doCArray: %@", sender);
uint64_t start = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += cArray[i];
}
[self displayResult:mach_absolute_time() - start];
}
// allocate NSArray and C Array
-(void) allocateArrays {
NSLog(@"allocateArrays");
// allocate c array
if(cArray) delete cArray;
cArray = new float[numberOfItems];
// allocate NSArray
[nsArray release];
nsArray = [[NSMutableArray alloc] initWithCapacity:numberOfItems];
// fill with random values
for(int i=0; i<numberOfItems; i++) {
// add number to c array
cArray[i] = random() * 1.0f/(RAND_MAX+1);
// add number to NSArray
NSNumber *number = [[NSNumber alloc] initWithFloat:cArray[i]];
[nsArray addObject:number];
[number release];
}
}
// callback for when slider is changed
-(IBAction) sliderChanged:(id)sender {
numberOfItems = sliderCount.value;
NSLog(@"sliderChanged: %@, %i", sender, numberOfItems);
NSString *str = [[NSString alloc] initWithFormat:@"%i items", numberOfItems];
[labelCount setText:str];
[str release];
[self allocateArrays];
}
//cleanup
- (void)dealloc {
[nsArray release];
if(cArray) delete cArray;
[super dealloc];
}
@end
Gönderen: memo.tv
////////////////////
Blokların tanıtılmasından bu yana kullanılabilir, bu bloklarla bir dizi yinelemeye izin verir. Sözdizimi hızlı numaralandırma kadar hoş değil, ama çok ilginç bir özellik var: eşzamanlı numaralandırma. Numaralandırma sırası önemli değilse ve işler kilitlenmeden paralel olarak yapılabilirse, bu çok çekirdekli bir sistemde önemli bir hızlanma sağlayabilir. Bununla ilgili daha fazla bilgi eşzamanlı numaralandırma bölümünde.
[myArray enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
[self doSomethingWith:object];
}];
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWith:object];
}];
/////////// NSFastEnumerator
Hızlı numaralandırmanın arkasındaki fikir, yinelemeyi optimize etmek için hızlı C dizisi erişimini kullanmaktır. Sadece geleneksel NSEnumerator'dan daha hızlı olması değil, aynı zamanda Objective-C 2.0 da çok özlü bir sözdizimi sağlar.
id object;
for (object in myArray) {
[self doSomethingWith:object];
}
/////////////////
NSEnumerator
Bu bir dış yineleme şeklidir: [myArray objectEnumerator] bir nesne döndürür. Bu nesnenin, nil döndürülene kadar bir döngüde çağırabileceğimiz nextObject yöntemi var.
NSEnumerator *enumerator = [myArray objectEnumerator];
id object;
while (object = [enumerator nextObject]) {
[self doSomethingWith:object];
}
/////////////////
objectAtIndex: numaralandırma
Bir tamsayıyı artıran bir for döngüsü kullanmak ve [myArray objectAtIndex: index] kullanarak nesneyi sorgulamak en temel numaralandırma biçimidir.
NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
[self doSomethingWith:[myArray objectAtIndex:index]];
}
////////////// Gönderen: darkdust.net
Üç yol:
//NSArray
NSArray *arrData = @[@1,@2,@3,@4];
// 1.Classical
for (int i=0; i< [arrData count]; i++){
NSLog(@"[%d]:%@",i,arrData[i]);
}
// 2.Fast iteration
for (id element in arrData){
NSLog(@"%@",element);
}
// 3.Blocks
[arrData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"[%lu]:%@",idx,obj);
// Set stop to YES in case you want to break the iteration
}];
each
Yöntemini ekle NSArray category
, çok ihtiyacın olacak
ObjectiveSugar'dan alınan kod
- (void)each:(void (^)(id object))block {
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj);
}];
}
Swift için
let arrayNumbers = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
// 1
for (index, value) in arrayNumbers.enumerated() {
print(index, value)
//... do somthing with array value and index
}
//2
for value in arrayNumbers {
print(value)
//... do somthing with array value
}
Bunu yap :-
for (id object in array)
{
// statement
}