objective-c - للصف - مشاريع الفيجوال بيسك جاهزة




كيف يمكنني تكرار ذلك على NSArray؟ (5)

أضف each طريقة في NSArray category ، ستحتاجها كثيرًا

رمز مأخوذ من ObjectiveSugar

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

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


إليك كيفية إعلان صفيف من السلاسل وتكرارها:

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

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

الرمز المفضل بشكل عام لـ 10.5 + / iOS.

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

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

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

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

إذا كنت تقوم بترميز OS 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 أو قبل ذلك

المصطلح القياسي لـ Pre-10.5 هو استخدام NSEnumerator وحلقة في حين ، مثل:

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

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

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

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


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

        //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. مع الإكمال التلقائي ننسى الكتابة مغلف التكرار.

لنظام التشغيل X 10.4.x والإصدارات السابقة:

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

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

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




enumeration