سؤال

أنا أبحث عن مستوى لغة إلى تكرار عبر NSArray.قانون بلدي يجب أن تكون مناسبة OS X 10.4+.

هل كانت مفيدة؟

المحلول

الرمز المفضل عموما لمدة 10.5 + / iOS.

for (id object in array) {
    // do something with object
}

يستخدم هذا البناء لتعداد الكائنات في مجموعة تتوافق مع NSFastEnumeration بروتوكول. يحتوي هذا النهج على ميزة السرعة لأنها تخزن مؤشرات إلى عدة كائنات (تم الحصول عليها عبر مكالمة طريقة واحدة) في مخزن مؤقت وتكرار من خلالها من خلال التقدم من خلال المخزن المؤقت باستخدام حساب مؤشر. هذا هو كثيراً أسرع من الاتصال -objectAtIndex: في كل مرة من خلال الحلقة.

تجدر الإشارة أيضا إلى أنه أثناء وجودك من الناحية الفنية تستطيع استخدم حلقة مقابل خطوة NSEnumerator, لقد وجدت أن هذا يلغي جميعا تقريبا كل ميزة السرعة لتعداد سريع. السبب هو أن الافتراضي NSEnumerator بداية شئ -countByEnumeratingWithState:objects:count: يضع كائن واحد فقط في المخزن المؤقت في كل مكالمة.

أبلغت هذا في radar://6296108 (التعداد السريع لل NSenumerators هو بطيئة) ولكن تم إرجاعه لأنه لا يتم إصلاحه. والسبب هو أن التعداد السريع مسبقا مجموعة من الكائنات، وإذا كنت ترغب في التعداد فقط إلى نقطة معينة فقط في العداد (على سبيل المثال، يتم العثور على كائن معين، أو يتم استيفاء الشرط) واستخدم نفس العداد بعد الانهيار من الحلقة، سيكون هذا هو الحال في كثير من الأشياء التي سيتم تخطيها عدة أشياء.

إذا كنت ترميزا لنظام التشغيل X 10.6 / iOS 4.0 وما فوق، فستكون لديك أيضا خيار استخدام واجهات برمجة التطبيقية المستندة إلى Block لتعداد الصفائف والمجموعات الأخرى:

[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
    // do something with object
}];

تستطيع ايضا استخذام -enumerateObjectsWithOptions:usingBlock: وتمرير NSEnumerationConcurrent و / أو NSEnumerationReverse كما حجة الخيارات.


10.4 أو سابقا

المصطلح القياسي لما قبل 10.5 هو استخدام NSEnumerator بينما الحلقة، مثل ذلك:

NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
  // do something with object
}

أوصي الاحتفاظ بها بسيطة. ربط نفسك إلى نوع الصفيف غير مرن، وزيادة السرعة المزعومة في استخدام -objectAtIndex: أمر ضئيل لتحسين التعداد السريع على 10.5+ على أي حال. (التعداد السريع يستخدم بالفعل حساب حساب مؤشر على هيكل البيانات الأساسي، ويزيل معظم الأسلوب استدعاء النفقات العامة.) الأمثل المبكر ليس فكرة جيدة - فهو ينتج عنه رمز Messier لحل مشكلة ليس عنق الزجاجة على أي حال.

عند استخدام -objectEnumerator, ، يمكنك التغيير بسهولة جدا إلى مجموعة غير قابلة للتعدي (مثل NSSet, ، مفاتيح في NSDictionary, ، وما إلى ذلك)، أو حتى التبديل إلى -reverseObjectEnumerator لتعداد صفيف للخلف، كل ذلك مع أي تغييرات رمز أخرى. إذا كان رمز التكرار في طريقة، فيمكنك نقله NSEnumerator والرمز لا يضطر حتى يهتم ماذا او ما انها تكرار. علاوة على ذلك، NSEnumerator (على الأقل أولئك الذين يوفرهم رمز Apple) يحتفظون بالتحصيل الذي يعداد طالما أن هناك المزيد من الأشياء، لذلك لا داعي للقلق بشأن المدة التي ستوفر فيها كائن التشغيل التلقائي.

ربما أكبر شيء NSEnumerator (أو التعداد السريع) يحميك من أن وجود مجموعة قابلة للتغيير (صفيف أو غير ذلك) تتغير تحتها بدون معارفك بينما كنت تعطل ذلك. إذا كنت تصل إلى الكائنات حسب الفهرس، فيمكنك تشغيل استثناءات غريبة أو أخطاء خارجية (في كثير من الأحيان بعد فترة طويلة بعد حدوث المشكلة) التي يمكن أن تكون مروعة لتصحيح الأخطاء. يحتوي التعداد باستخدام إحدى التعابير القياسية على سلوك "فشل سريع"، لذلك سيظهر المشكلة (الناجمة عن التعليمات البرمجية غير الصحيحة) على الفور عند محاولة الوصول إلى الكائن التالي بعد حدوث طفرة. نظرا لأن البرامج تحصل على أكثر تعقيدا ومتعدد الخيوط، أو حتى تعتمد على شيء قد يعدل رمز الطرف الثالث، يصبح رمز التعداد الهش يصبح مشكلة بشكل متزايد. التغليف والتجريد FTW! :-)


نصائح أخرى

لنظام التشغيل × 10.4.x وال السابق:

 int i;
 for (i = 0; i < [myArray count]; i++) {
   id myArrayElement = [myArray objectAtIndex:i];
   ...do something useful with myArrayElement
 }

لنظام التشغيل × 10.5.x (أو iPhone) وما بعده:

for (id myArrayElement in myArray) {
   ...do something useful with myArrayElement
}

نتائج اختبار التعليمات البرمجية المصدر أدناه (يمكنك تعيين عدد من التكرارات في التطبيق).الوقت بالمللي ثانية و كل إدخال في المتوسط نتيجة تشغيل الاختبار 5-10 مرات.لقد وجدت هذا عموما هو دقيق 2-3 ارقام كبيرة و بعد ذلك سوف تختلف مع كل تشغيل.أن يعطي هامش خطأ أقل من 1%.الاختبار كان يعمل على الجيل الثالث 3G اي فون كما أن الهدف منصة كنت مهتما في.

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

الفئات التي تقدمها الكاكاو على التعامل مع مجموعات البيانات (NSDictionary, NSArray ، NSSet.... الخ) توفر واجهة جميلة جدا لإدارة المعلومات دون الحاجة إلى القلق حول البيروقراطية في إدارة الذاكرة تخصيص الخ.بالطبع هذا لا يأتي بتكلفة بالرغم من ذلك.أعتقد أنه من الواضح جدا أن أقول باستخدام NSArray من NSNumbers سيكون أبطأ من ج مجموعة من يطفو على التكرار بسيطة, لذلك قررت أن تفعل بعض الفحوصات وكانت النتائج صادمة جدا!لم أكن أتوقع أن يكون بهذا السوء.ملاحظة:هذه الاختبارات التي أجريت على الجيل الثالث 3G اي فون كما أن الهدف منصة كنت مهتما في.

في هذا الاختبار أفعل بسيط جدا الوصول العشوائي مقارنة الأداء بين ج تطفو* و NSArray من NSNumbers

لقد خلق حلقة بسيطة لتلخيص محتويات كل مجموعة والوقت لهم باستخدام mach_absolute_time().على NSMutableArray يأخذ في المتوسط 400 مرات أطول!!(لا 400 في المئة فقط 400 مرات أطول!هذا 40,000% أطول!).

الرأس:

// Array_Speed_TestViewController.ح

// مجموعة اختبار سرعة

// تم إنشاؤها بواسطة محمد Akten على 05/02/2009.

// حقوق النشر MSA صور Ltd.2009.جميع الحقوق محفوظة.

#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

التنفيذ:

// Array_Speed_TestViewController.م

// مجموعة اختبار سرعة

// تم إنشاؤها بواسطة محمد Akten على 05/02/2009.

// حقوق النشر MSA صور Ltd.2009.جميع الحقوق محفوظة.

    #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

من :memo.tv

////////////////////

متاح منذ إدخال كتل ، وهذا يسمح تكرار مجموعة مع كتل.بناء الجملة ليس لطيفا كما سريع التعداد ، ولكن هناك ميزة واحدة مثيرة جدا للاهتمام:المتزامنة التعداد.إذا كان تعداد أمر لا أهمية الوظائف التي يمكن أن يتم بالتوازي دون قفل, هذا يمكن أن توفر قدرا كبيرا من تسريع على multi-core النظام.المزيد حول ذلك في المتزامنة التعداد القسم.

[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

الفكرة وراء سريع التعداد هو استخدام سريع C مجموعة الوصول إلى تحسين التكرار.ليس فقط هو أنه من المفترض أن تكون أسرع من التقليدية NSEnumerator ، ولكن الهدف-C 2.0 يوفر أيضا موجزة جدا في بناء الجملة.

id object;
for (object in myArray) {
    [self doSomethingWith:object];
}

/////////////////

NSEnumerator

هذا هو شكل من أشكال الخارجية التكرار:[myArray objectEnumerator] بإرجاع كائن.يحتوي هذا الكائن على طريقة nextObject نتمكن من الاتصال في حلقة حتى تعود النيل

NSEnumerator *enumerator = [myArray objectEnumerator];
id object;
while (object = [enumerator nextObject]) {
    [self doSomethingWith:object];
}

/////////////////

objectAtIndex:التعداد

باستخدام حلقة for مما يزيد عدد صحيح و الاستعلام عن كائن باستخدام [myArray objectAtIndex:فهرس] هو أبسط شكل من التعداد.

NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
    [self doSomethingWith:[myArray objectAtIndex:index]];
}

////////////// من :darkdust.net

الطرق الثلاث هي:

        //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
    }];
  1. هي أسرع طريقة في التنفيذ، و 3. مع تنسيق الإكمال التلقائي حول مغلف التكرار.

يضيف each طريقة في الخاص بك NSArray category, ، ستحتاج إليها كثيرا

رمز مأخوذ من الاعتراضات الأجواء

- (void)each:(void (^)(id object))block {
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        block(obj);
    }];
}

إليك الطريقة التي تعلن فيها مجموعة من الأوتار وتكررها:

NSArray *langs = @[@"es", @"en", @"pt", @"it", @"fr"];

for (int i = 0; i < [langs count]; i++) {
  NSString *lang = (NSString*) [langs objectAtIndex:i];
  NSLog(@"%@, ",lang);
}

لسريع

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
}

افعل هذا :-

for (id object in array) 
{
        // statement
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top