কেন অ্যাপল এআরসি-র অধীনে সিঙ্গলটন প্যাটার্নটি প্রয়োগের জন্য ডিসপ্যাচ_অনস ব্যবহার করার পরামর্শ দেয়?


305

এআরসি-র অধীনে সিঙ্গলটনের শেয়ার্ড ইনস্ট্যান্স অ্যাকসেসরে প্রেরণ_অনস ব্যবহার করার সঠিক কারণ কী?

+ (MyClass *)sharedInstance
{
    //  Static local predicate must be initialized to 0
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

পটভূমিতে অবিচ্ছিন্নভাবে সিঙ্গলটন ইনস্ট্যান্ট করা কি খারাপ ধারণা নয়? আমি বোঝাতে চাইছি যদি আমি সেই ভাগ করা দৃষ্টান্তটি অনুরোধ করি এবং অবিলম্বে এটির উপর নির্ভর করি তবে ডিসপ্যাচ_নস ক্রিসমাস পর্যন্ত আমার অবজেক্ট তৈরি করতে সময় নেয়? এটা ঠিক সঙ্গে সঙ্গে ফিরে না? কমপক্ষে এটি গ্র্যান্ড সেন্ট্রাল ডিসপ্যাচের পুরো পয়েন্ট বলে মনে হচ্ছে।

তাহলে তারা কেন এটি করছে?


Note: static and global variables default to zero.
ikkentim

উত্তর:


418

dispatch_once()একেবারে সিঙ্ক্রোনাস। সমস্ত জিসিডি পদ্ধতিগুলি অবিচ্ছিন্নভাবে কাজ করে না (পয়েন্টে dispatch_sync()সিঙ্ক্রোনাস হয়)। dispatch_once()নিম্নলিখিত আইডিয়মের পরিবর্তে ব্যবহার :

+ (MyClass *)sharedInstance {
    static MyClass *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[MyClass alloc] init];
        }
    }
    return sharedInstance;
}

dispatch_once()এটির থেকে লাভ হ'ল এটি দ্রুত। এটি শব্দার্থগতভাবে পরিষ্কারও, কারণ এটি আপনার ভাগ করা ইনস্ট্যান্সের বরাদ্দ করা একাধিক থ্রেড থেকেও রক্ষা করে - যদি তারা সকলেই একই সময়ে চেষ্টা করে। এটি দুটি দৃষ্টান্ত তৈরি করতে দেয় না। এর সম্পূর্ণ ধারণাটি dispatch_once()হ'ল "একবার এবং কেবল একবার কিছু করা", যা আমরা যা করছি তা অবিকল।


4
যুক্তিটির স্বার্থে আমার নোট করা উচিত যে ডকুমেন্টেশনগুলি এটি সিঙ্ক্রোনালি মৃত্যুদন্ড কার্যকর করা হচ্ছে না বলে বলে। এটি কেবলমাত্র বলে যে এক সাথে একাধিক অনুরোধগুলি সিরিয়ালযুক্ত করা হবে।
বিশেষজ্ঞ

5
আপনি দাবি করেছেন যে এটি দ্রুত - কত দ্রুত? আপনি সত্য বলছেন না এমন ভাবার কোনও কারণ নেই, তবে আমি একটি সাধারণ মানদণ্ড দেখতে চাই।
জোশুয়া গ্রস

29
আমি সবেমাত্র একটি সাধারণ বেঞ্চমার্ক করেছি (আইফোন 5 এ) এবং দেখে মনে হচ্ছে @ সিংক্রোনাইজডের চেয়ে প্রায় 2x দ্রুত গতিতে dispatch_once।
জোশুয়া গ্রস

3
@ রেনেডোহন: আপনি যদি 100% নিশ্চিত হন যে কেউ কখনও এই পদ্ধতিটিকে অন্য কোনও থ্রেড থেকে কল করেন না, তবে এটি কার্যকর হয়। তবে ব্যবহার dispatch_once()করা সত্যিই সহজ (বিশেষত কারণ Xcode এমনকি এটি আপনার জন্য একটি সম্পূর্ণ কোড স্নিপেটে স্বয়ংক্রিয়ভাবে পূর্ণ করে দেবে) এবং এর অর্থ এই পদ্ধতিটি থ্রেড-নিরাপদ হওয়া দরকার কিনা তা আপনাকে কখনও বিবেচনা করতে হবে না।
লিলি ব্যালার্ড

1
@ সিউইং: আসলে, এটি সত্য নয়। প্রথমত, +initializeক্লাসটি স্পর্শ করার আগে যা কিছু করা হয়েছিল তা ঘটতে পারে, আপনি এখনও নিজের ভাগাভাগি করা দৃষ্টান্ত তৈরি করার চেষ্টা না করলেও। সাধারণভাবে, অলস সূচনা (কেবল যখন প্রয়োজন তখন কিছু তৈরি করা) ভাল। দ্বিতীয়ত, এমনকি আপনার কর্মক্ষমতা দাবিও সত্য নয়। dispatch_once()বলার অপেক্ষা রাখে না সময় প্রায় ঠিক একই পরিমাণ সময় লাগে if (self == [MyClass class])মধ্যে +initialize। আপনার যদি ইতিমধ্যে একটি থাকে +initialize, তবে হ্যাঁ সেখানে ভাগ করে নেওয়া উদাহরণটি তৈরি করা দ্রুততর, তবে বেশিরভাগ শ্রেণি তা ​​করে না।
লিলি বালার্ড

41

কারণ এটি কেবল একবারই চলবে। সুতরাং আপনি যদি বিভিন্ন থ্রেড থেকে দু'বার চেষ্টা করে এটি অ্যাক্সেস করেন তবে এটি সমস্যার কারণ হবে না।

মাইকের অ্যাশয়ের সিঙ্গেলটনের ব্লগ পোস্টের যত্ন এবং খাওয়ানো সম্পর্কে একটি সম্পূর্ণ বিবরণ রয়েছে ।

সমস্ত জিসিডি ব্লক অ্যাসিঙ্ক্রোনালি চালিত হয় না।


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