যখন enumerateObजेজস ব্যবহার ব্লক বনাম ব্যবহার করবেন


150

সুস্পষ্ট পার্থক্য ছাড়াও:

  • ব্যবহার enumerateObjectsUsingBlock সূচক এবং অবজেক্ট উভয়ের প্রয়োজন হলে
  • ব্যবহার করবেন না enumerateObjectsUsingBlockযখন আপনাকে স্থানীয় ভেরিয়েবলগুলি সংশোধন করার দরকার তখন (আমি এই সম্পর্কে ভুল ছিলাম, বুবুমের উত্তর দেখুন)

হয় enumerateObjectsUsingBlockসাধারণত বিবেচিত ভালো বা খারাপ যখন for (id obj in myArray)এছাড়াও কাজ করবে? সুবিধাগুলি / অসুবিধাগুলি কী কী (উদাহরণস্বরূপ এটি কম বা কম পারফরম্যান্ট)?


1
আমার বর্তমান সূচকের প্রয়োজন হলে এটি ব্যবহার করতে চাই like
বেসি

উত্তর:


349

শেষ পর্যন্ত, আপনি যে কোনও প্যাটার্নটি ব্যবহার করতে চান তা ব্যবহার করুন এবং প্রসঙ্গে আরও স্বাভাবিকভাবেই আসুন।

যদিও for(... in ...)বেশ সুবিধাজনক এবং সিনট্যাক্টিকালি সংক্ষিপ্ত, enumerateObjectsUsingBlock:এর বেশ কয়েকটি বৈশিষ্ট্য রয়েছে যা আকর্ষণীয় প্রমাণিত হতে পারে বা নাও পারে:

  • enumerateObjectsUsingBlock:দ্রুত গণনার চেয়ে দ্রুত বা দ্রুত হবে ( গণনা প্রয়োগের for(... in ...)জন্য NSFastEnumerationসমর্থনটি ব্যবহার করে )। দ্রুত গণনার জন্য অভ্যন্তরীণ প্রতিনিধিত্ব থেকে দ্রুত গণনার জন্য উপস্থাপনার অনুবাদ দরকার। সেখানে ওভারহেড আছে। ব্লক-ভিত্তিক গণনা সংগ্রহ শ্রেণিকে দেশীয় স্টোরেজ বিন্যাসের দ্রুততম ট্র্যাভারসাল হিসাবে সামগ্রীগুলি গণনা করার অনুমতি দেয়। অ্যারেগুলির জন্য সম্ভবত অপ্রাসঙ্গিক, তবে অভিধানের ক্ষেত্রে এটি বিশাল পার্থক্য হতে পারে।

  • "যখন আপনাকে স্থানীয় ভেরিয়েবলগুলি সংশোধন করার দরকার হয় তখন এনুমারেট অবজেক্টস ইউজিং ব্লক ব্যবহার করবেন না" - সত্য নয়; আপনি আপনার স্থানীয়দের হিসাবে ঘোষণা করতে পারেন __blockএবং তারা ব্লকে লিখিত হতে পারে।

  • enumerateObjectsWithOptions:usingBlock: একসাথে বা বিপরীত গণনা সমর্থন করে।

  • অভিধান সহ, ব্লক ভিত্তিক গণনা একসাথে কী এবং মানটি পুনরুদ্ধার করার একমাত্র উপায় way

ব্যক্তিগতভাবে, আমি ব্যক্তিগত পছন্দ থেকে enumerateObjectsUsingBlock:বেশি for (... in ...), তবে - আবার ব্যবহার করি ।


16
বাহ, খুব তথ্যপূর্ণ। আমি আশা করি আমি এই দুটি উত্তরই গ্রহণ করতে পারতাম, তবে আমি চকের সাথে যাচ্ছি কারণ এটি আমার সাথে আরও কিছুটা অনুরণিত হয়। এছাড়াও, আমি__ ব্লক অনুসন্ধান করার সময় আপনার ব্লগটি ( ফ্রিডা.কম / বিবাম / 2009 / 08 / 29 / blocks-tips- কৌশল ) খুঁজে পেয়েছি এবং আরও শিখেছি। ধন্যবাদ.
পল হুইলার

8
রেকর্ডের জন্য, ব্লক-ভিত্তিক শুমার সবসময় নয় "হিসাবে দ্রুত বা দ্রুত" mikeabdullah.net/slow-block-based-dictionary-enumeration.html
মাইক আব্দুল্লাহ

2
আপনি যদি আলাদা থ্রেডে মৃত্যুদন্ড কার্যকর করতে বলেন তবে @ ভানডুট্রান ব্লকগুলি কেবল একটি পৃথক থ্রেডে কার্যকর করা হবে। আপনি যদি না গণনার
একচ্ছত্র

2
নিক লকউড এই সম্পর্কে একটি দুর্দান্ত নিবন্ধ করেছিলেন এবং এটি enumerateObjectsUsingBlockএখনও অ্যারে এবং সেটগুলির জন্য দ্রুত গণনার তুলনায় উল্লেখযোগ্যভাবে ধীর হয়ে গেছে বলে মনে হয়। আমি ভাবছি কেন? iosdevelopertips.com/objective-c/…
বব স্প্রিন

2
যদিও এটি enumerateObjectsUsingBlockএকধরণের বাস্তবায়নের বিশদ, তবে এই উত্তরটিতে দুটি পদ্ধতির মধ্যে পার্থক্যের মধ্যে উল্লেখ করা উচিত যা ব্লকের প্রতিটি অনুরোধকে একটি অটোরিলেজ পুল (কমপক্ষে ওএস এক্স 10.10 হিসাবে) দিয়ে আবৃত করে। এটি এর সাথে তুলনা করে পারফরম্যান্সের পার্থক্যটি ব্যাখ্যা করে for in
পোল

83

সাধারণ গণনার জন্য, কেবলমাত্র দ্রুত গণনা (অর্থাত একটি for…in…লুপ) ব্যবহার করা আরও প্রচ্ছন্ন বিকল্প। ব্লক পদ্ধতিটি সামান্য দ্রুত হতে পারে তবে বেশিরভাগ ক্ষেত্রে এটি বেশিরভাগ ক্ষেত্রেই আসে না - কয়েকটি প্রোগ্রাম সিপিইউ দ্বারা আবদ্ধ হয় এবং তারপরেও এটি বিরল যে অভ্যন্তরের গণনার চেয়ে লুপটি নিজেই একটি বাধা হয়ে দাঁড়াবে।

একটি সাধারণ লুপ আরও স্পষ্টভাবে পড়ে। এখানে দুটি সংস্করণের বয়লারপ্লেট রয়েছে:

for (id x in y){
}

[y enumerateObjectsUsingBlock:^(id x, NSUInteger index, BOOL *stop){
}];

এমনকি আপনি সূচকটি ট্র্যাক করতে কোনও ভেরিয়েবল যুক্ত করলেও সরল লুপটি পড়া সহজ।

আপনার কখন ব্যবহার করা উচিত enumerateObjectsUsingBlock:? আপনি যখন পরে বা একাধিক জায়গায় চালিত করতে কোনও ব্লক সংরক্ষণ করছেন। আপনি যখন লুপ বডিটির ওভারড্রাস্ট রিপ্লেসমেন্টের পরিবর্তে প্রথম শ্রেণীর ফাংশন হিসাবে কোনও ব্লকটি ব্যবহার করছেন তখন এটি ভাল।


5
enumerateObjectsUsingBlock:হয় একই ক্ষেত্রে বা সমস্ত ক্ষেত্রে দ্রুত গণনার চেয়ে দ্রুত হবে faster for(... in ...)অভ্যন্তরীণ ডেটা স্ট্রাকচারের অন্তর্বর্তীকালীন উপস্থাপনা সরবরাহের জন্য সংগ্রহের প্রয়োজন এমন দ্রুত গণনা ব্যবহার করে। আপনি যেমন নোট হিসাবে, সম্ভবত অপ্রাসঙ্গিক।
বুবুম

4
+1When you're storing a block to execute later or in multiple places. It's good for when you're actually using a block as a first-class function rather than an overwrought replacement for a loop body.
স্টিভ

7
@ বুবাম আমার নিজের পরীক্ষাগুলি দেখায় যে enumerateObjects...লুপের সাহায্যে ধীরে ধীরে দ্রুত গণনা করা যেতে পারে। আমি এই পরীক্ষা কয়েক হাজার বার চালিয়েছি; ব্লক এবং লুপ শরীরের কোডের একই একক লাইন ছিল: [(NSOperation *)obj cancel];। গড়: দ্রুত এনাম লুপ - -[JHStatusBar dequeueStatusMessage:] [Line: 147] Fast enumeration time (for..in..loop): 0.000009এবং ব্লকের জন্য - -[JHStatusBar dequeueStatusMessage:] [Line: 147] Enumeration time using block: 0.000043। আজব যে সময়ের পার্থক্য এত বড় এবং সামঞ্জস্যপূর্ণ তবে স্পষ্টতই, এটি একটি খুব নির্দিষ্ট পরীক্ষার কেস।
chown

42

যদিও এই প্রশ্নটি পুরানো, জিনিসগুলি পরিবর্তিত হয়নি, গৃহীত উত্তরটি ভুল।

enumerateObjectsUsingBlockএপিআই রহিত বোঝানো হয় নি for-in, কিন্তু একটি সম্পূর্ণ ভিন্ন ব্যবহারের ক্ষেত্রে জন্য:

  • এটি স্বেচ্ছাসেবী, অ-স্থানীয় যুক্তির প্রয়োগের অনুমতি দেয়। উদাহরণস্বরূপ আপনার অ্যারেতে ব্লকটি কী ব্যবহার করে তা জানতে হবে না।
  • বড় সংগ্রহ বা ভারী গণনার জন্য একত্রে গণনা ( withOptions:প্যারামিটার ব্যবহার করে )

দ্রুত গণনা সহ for-inএখনও একটি সংগ্রহের গণনা করার আইডেম্যাটিক পদ্ধতি।

কোডের বংশবৃদ্ধি, পাঠযোগ্যতা এবং অতিরিক্ত অপ্টিমাইজেশানগুলি থেকে দ্রুত গণনার উপকার হয় যা এটিকে অপ্রাকৃতিকভাবে দ্রুত করে তোলে। লু-লুপের চেয়ে পুরানো সি এর চেয়ে দ্রুত!

একটি দ্রুত পরীক্ষা সিদ্ধান্তে পৌঁছেছে যে ২০১৪ সালে আইওএস on-তে, enumerateObjectsUsingBlockধারাবাহিকভাবে ইন-ইন (১০০ আইটেমির অ্যারের ১ মিমি পুনরাবৃত্তির উপর ভিত্তি করে) তুলনায় 700০০% ধীর গতিতে থাকে।

কর্মক্ষমতা এখানে কি বাস্তব ব্যবহারিক উদ্বেগ?

বিরল ব্যতিক্রম ছাড়া অবশ্যই না।

পয়েন্টটি হ'ল enumerateObjectsUsingBlock:ওভার ব্যবহারের খুব কম সুবিধা রয়েছে তা দেখানোর জন্যfor-in কারণ ব্যতীত । এটি কোডটি আরও পঠনযোগ্য ... বা দ্রুত ... বা থ্রেড-নিরাপদ করে না। (অন্য একটি সাধারণ ভুল ধারণা)।

পছন্দটি ব্যক্তিগত পছন্দকে নেমে আসে। আমার জন্য, আইডোমেটিক এবং পঠনযোগ্য বিকল্পটি জয়ী। এই ক্ষেত্রে, এটি ব্যবহার করে দ্রুত গণনা for-in

মাপকাঠি:

NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
    arr[i] = [NSString stringWithFormat:@"%d", i];
}
int i;
__block NSUInteger length;

i = 1000 * 1000;
uint64_t a1 = mach_absolute_time();
while (--i > 0) {
    for (NSString *s in arr) {
        length = s.length;
    }
}
NSLog(@"For-in %llu", mach_absolute_time()-a1);

i = 1000 * 1000;
uint64_t b1 = mach_absolute_time();
while (--i > 0) {
    [arr enumerateObjectsUsingBlock:^(NSString *s, NSUInteger idx, BOOL *stop) {
        length = s.length;
    }];
}
NSLog(@"Enum %llu", mach_absolute_time()-b1);

ফলাফল:

2014-06-11 14:37:47.717 Test[57483:60b] For-in 1087754062
2014-06-11 14:37:55.492 Test[57483:60b] Enum   7775447746

4
আমি নিশ্চিত করতে পারি যে ম্যাকবুক প্রো রেটিনা 2014 এ একই পরীক্ষা চালানো enumerateObjectsUsingBlockআসলে 5X ধীর। এটি দৃশ্যত ব্লকের প্রতিটি অনুরোধকে মোড়ানো একটি অটোরিলেজ পুলের কারণে, যা ঘটনার for inক্ষেত্রে ঘটে না ।
পোল

2
আমি নিশ্চিত করেছি যে enumerateObjectsUsingBlock:এখনও বাস্তব আইফোন 6 আইওএস 9-এ 4x ধীর, বিল্ডিংয়ের জন্য এক্সকোড 7.x ব্যবহার করে।
Cœur

1
জানানোর জন্য ধন্যবাদ! আমি আশা করি এই উত্তরটি এতটা সমাহিত না হয়ে গেছে ... কিছু লোকেরা enumerateসিনট্যাক্সের মতোই লাগে কারণ এটি এফপির মতো মনে হয় এবং পারফরম্যান্স বিশ্লেষণ শুনতে চায় না to
আদম কাপলান

1
যাইহোক, এটি কেবল অটোরিলিজ পুলের কারণে নয়। আরও অনেক স্ট্যাক ঠেলাঠেলি করছে এবং পপ করছেenumerate:
আদম কাপলান

24

পারফরম্যান্স সম্পর্কে প্রশ্নের উত্তর দেওয়ার জন্য, আমি আমার পারফরম্যান্স পরীক্ষার প্রকল্পটি ব্যবহার করে কিছু পরীক্ষা করেছি । আমি জানতে চেয়েছিলাম যে অ্যারেতে সমস্ত অবজেক্টে একটি বার্তা প্রেরণের তিনটি বিকল্পের মধ্যে কোনটি দ্রুততম।

বিকল্পগুলি ছিল:

1) MakeObjectsPerforSelector

[arr makeObjectsPerformSelector:@selector(_stubMethod)];

2) দ্রুত গণনা এবং নিয়মিত বার্তা প্রেরণ

for (id item in arr)
{
    [item _stubMethod];
}

3) গণনাঅবজেক্টস ইউজিং ব্লক এবং নিয়মিত বার্তা প্রেরণ

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 
 {
     [obj _stubMethod];
 }];

দেখা যাচ্ছে যে মেকওবজেক্টস পারফর্মসিলিেক্টরটি এখন পর্যন্ত সবচেয়ে ধীর ছিল। এটি দ্রুত গণনা হিসাবে দ্বিগুণ সময় নিয়েছে। এবং এনুমারিওবজেক্টস ইউজিং ব্লকটি দ্রুততম ছিল, এটি দ্রুত পুনরাবৃত্তির চেয়ে প্রায় 15-20% দ্রুত ছিল।

সুতরাং আপনি যদি সেরা সম্ভাব্য পারফরম্যান্স সম্পর্কে খুব উদ্বিগ্ন হন তবে এনুমারেটঅবজেক্টস ইউজিং ব্লক ব্যবহার করুন। তবে মনে রাখবেন যে কোনও কোনও ক্ষেত্রে সংগ্রহটি গণনা করতে যে সময় লাগে তা দ্বিগুণ হয় যা আপনি প্রতিটি বস্তুকে কার্যকর করতে চান তার জন্য যে কোনও কোড চালাতে সময় লাগে।


আপনি আপনার নির্দিষ্ট পরীক্ষা নির্দেশ করতে পারেন? দেখে মনে হচ্ছে আপনি একটি ভুল উত্তর দিয়েছেন।
সিউর

3

যখন আপনি নেস্টেড লুপগুলি ভাঙতে চান তখন এটি বহিরাগত লুপ হিসাবে গণ্যকারী অবজেক্টস ইউজিং ব্লক ব্যবহার করা মোটামুটি কার্যকর।

যেমন

[array1 enumerateObjectsUsingBlock:^(id obj1, NSUInteger idx, BOOL * _Nonnull stop) {
  for(id obj2 in array2) {
    for(id obj3 in array3) {
      if(condition) {
        // break ALL the loops!
        *stop = YES;
        return;
      }
    }
  }
}];

বিকল্পটি গোটো স্টেটমেন্ট ব্যবহার করছে।


1
অথবা আপনি এখানে যেমন করেছেন ঠিক তেমন পদ্ধতি থেকে ফিরে আসতে পারেন :
অ্যাডাম কাপলান

1

পারফরম্যান্সে বিস্তৃত তুলনা শুরু করার জন্য @ ববম এবং @ চককে ধন্যবাদ। এটা তুচ্ছ জানার জন্য খুশি। আমার সাথে মনে হয়েছে:

  • for (... in ...)- আমার ডিফল্ট গোটো হিসাবে আমার কাছে আরও স্বজ্ঞাত, যে কোনও বাস্তব পছন্দের চেয়ে এখানে আরও প্রোগ্রামিং ইতিহাস - ক্রস ল্যাঙ্গুয়েজ পুনরায় ব্যবহার, আইডিই অটো সম্পূর্ণ হওয়ার কারণে বেশিরভাগ ডেটা স্ট্রাকচারের জন্য কম টাইপ করা: পি।

  • enumerateObject...- যখন বস্তু এবং সূচক অ্যাক্সেস প্রয়োজন হয়। এবং অ-অ্যারে বা অভিধানের কাঠামোগুলিতে অ্যাক্সেস করার সময় (ব্যক্তিগত পছন্দ)

  • for (int i=idx; i<count; i++) - অ্যারেগুলির জন্য, যখন আমাকে একটি শূন্য-সূচক থেকে শুরু করতে হবে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.