অবজেক্টিভ-সি তে জিসিডির ডিসপ্যাচ_অনস ব্যবহার করে সিঙ্গলটন তৈরি করুন


341

আপনি যদি আইওএস 4.0 বা তারপরের উপর লক্ষ্য রাখতে পারেন

জিসিডি ব্যবহার করে, অবজেক্টিভ-সিতে (থ্রেড নিরাপদ) সিঙ্গেলটন তৈরি করা কি সেরা উপায়?

+ (instancetype)sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

2
ক্লাসের ব্যবহারকারীদের বরাদ্দ / অনুলিপি কল করতে বাধা দেওয়ার কোনও উপায় আছে কি?
নিকোলাস মিয়ারি

3
dispatch_once_t এবং dispatch_once ৪.১ নয়, 4.0.০ তে প্রবর্তিত হয়েছে বলে মনে হয় (দেখুন: বিকাশকারী.এপ্লে /
বেন ফ্লিন

1
এই পদ্ধতিটি সমস্যায় পরিণত হয় যদি ডিআইএর জন্য সিঙ্গলটন অবজেক্টের প্রয়োজন হয়। ম্যাট গ্যালাগারের কোড কয়েকবারের বেশি সময়ে আমার জন্য কাজ করেছে। cocoawithlove.com/2008/11/...
গ্রেগ

1
আমি এই উদাহরণে এর অসঙ্গতি জানি; তবে লোকেরা কেন 'নতুন' বেশি ব্যবহার করে না। প্রেরণ_অনসেস (এবং একবার, {{শেয়ারডআইনস্ট্যান্স = [স্ব নতুন);} কেবল খানিকটা নিবিড় দেখায় এটি + থিম বরাদ্দের সমতুল্য
ক্রিস হ্যাটন

3
রিটার্নের ধরণটি ব্যবহার শুরু করার বিষয়ে নিশ্চিত হন instancetype। পরিবর্তে কোডটি ব্যবহার করার সময় কোড সমাপ্তি আরও ভাল id
মিঃ রজার্স

উত্তর:


215

আপনার শ্রেণীর উদাহরণ তৈরি করার জন্য এটি একটি নিখুঁতভাবে গ্রহণযোগ্য এবং থ্রেড-নিরাপদ উপায়। এটি প্রযুক্তিগতভাবে "সিঙ্গলটন" নাও হতে পারে (এটিতে কেবল এই বস্তুগুলির মধ্যে 1 টিই থাকতে পারে) তবে যতক্ষণ আপনি কেবলমাত্র [Foo sharedFoo]অবজেক্টটি অ্যাক্সেস করার জন্য পদ্ধতিটি ব্যবহার করেন এটি যথেষ্ট ভাল is


4
কিভাবে আপনি এটি মুক্তি?
samvermette

65
@ সমারমেট আপনি না একটি সিঙ্গলটনের বিষয়টি হ'ল এটি সর্বদা উপস্থিত থাকবে। এইভাবে, আপনি এটি প্রকাশ করবেন না, এবং প্রক্রিয়াটি প্রস্থান হওয়ার সাথে সাথে স্মৃতি পুনরুদ্ধার হয়।
ডেভ দেলং

6
@ ডেভ ডেলং: আমার মতে সিঙ্গেলটন থাকার উদ্দেশ্যটি এর অমরত্বের নিশ্চয়তা নয়, তবে আমাদের দৃ .় বিশ্বাস রয়েছে যে আমাদের একটি উদাহরণ রয়েছে। যদি সেই সিঙ্গেলটন একটি সেমফোর হ্রাস পায়? আপনি কেবল নির্বিচারে বলতে পারবেন না যে এটি সর্বদা উপস্থিত থাকবে।
jacekmigacz

4
@ হুলিহুপ হ্যাঁ, এর ডকুমেন্টেশনে । "যদি একাধিক থ্রেড থেকে একযোগে ডাকা হয়, ব্লকটি শেষ না হওয়া পর্যন্ত এই ফাংশনটি সিঙ্ক্রোনসিটি অপেক্ষা করে।"
কেভিন

3
@ ওয়াল্টারমার্টিন ভার্গাস-পেনার দৃ reference় রেফারেন্সটি স্ট্যাটিক ভেরিয়েবল
ডেভ দেলং

36

instancetype

instancetypeObjective-Cপ্রতিটি নতুন রিলিজের সাথে আরও যুক্ত হওয়ার সাথে কেবলমাত্র বহু ভাষা বর্ধনের মধ্যে একটি ।

এটা জানুন, এটা ভালবাসা।

এবং কীভাবে নিম্ন-স্তরের বিশদগুলিতে মনোযোগ দেওয়া আপনাকে উদ্দেশ্য-সি রূপান্তর করার জন্য শক্তিশালী নতুন উপায়ে অন্তর্দৃষ্টি দিতে পারে তার একটি উদাহরণ হিসাবে এটি গ্রহণ করুন।

এখানে উল্লেখ করুন: উদাহরণস্বরূপ


+ (instancetype)sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;

    dispatch_once(&once, ^
    {
        sharedInstance = [self new];
    });    
    return sharedInstance;
}

+ (Class*)sharedInstance
{
    static dispatch_once_t once;
    static Class *sharedInstance;

    dispatch_once(&once, ^
    {
        sharedInstance = [self new];
    });    
    return sharedInstance;
}

4
আশ্চর্যজনক টিপ, ধন্যবাদ! উদাহরণস্বরূপ একটি প্রাসঙ্গিক কীওয়ার্ড যা কোনও পদ্ধতি সম্পর্কিত ফলাফলের ধরণটি দেয় এমন সিগন্যালের জন্য ফলাফল প্রকার হিসাবে ব্যবহার করা যেতে পারে। ... উদাহরণস্বরূপ, সংকলকটি সঠিকভাবে অনুমান করবে।
ফ্যাটি

1
এখানে দুটি স্নিপেটের অর্থ কী তা আমার কাছে স্পষ্ট নয়, তারা কি একে অপরের সমতুল্য? একজনের কাছে অপরটির চেয়ে ভাল? লেখক যদি এর জন্য কিছুটা ব্যাখ্যা যোগ করতে পারেন তবে চমৎকার হবে।
গ্যালাকটিকা

33

MySingleton.h

@interface MySingleton : NSObject

+(instancetype)sharedInstance;

+(instancetype)alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
-(instancetype)init __attribute__((unavailable("init not available, call sharedInstance instead")));
+(instancetype)new __attribute__((unavailable("new not available, call sharedInstance instead")));
-(instancetype)copy __attribute__((unavailable("copy not available, call sharedInstance instead")));

@end

MySingleton.m

@implementation MySingleton

+(instancetype)sharedInstance {
    static dispatch_once_t pred;
    static id shared = nil;
    dispatch_once(&pred, ^{
        shared = [[super alloc] initUniqueInstance];
    });
    return shared;
}

-(instancetype)initUniqueInstance {
    return [super init];
}

@end

দীক্ষা কীভাবে উপলব্ধ নয়? এটি কমপক্ষে একটির জন্য পাওয়া যায় না init?
মধু

2
সিঙ্গেলনের একটি মাত্র অ্যাক্সেস পয়েন্ট থাকা উচিত। এবং এই পয়েন্টটি শেয়ার করা ইনস্ট্যান্স। আপনি যদি অন্য একটি সিঙ্গলটন উদাহরণ তৈরি করতে পারেন তার চেয়ে আমাদের কাছে * .h ফাইলে দীক্ষা পদ্ধতি থাকে। এটি একটি সিঙ্গলটনের সংজ্ঞাটির বিরোধিতা করে।
সের্গে পেট্রুক

1
@ আসমা 22 __ট্রিবিউট __ ((অনুপলব্ধ ()) এই পদ্ধতিগুলি ব্যবহারের জন্য উপলব্ধ করে না another অন্য কোনও প্রোগ্রামার যদি অনুপলব্ধ হিসাবে চিহ্নিত পদ্ধতি ব্যবহার করতে চান তবে সে ত্রুটি পেয়ে যায়
সের্গেই পেট্রুক

1
আমি পুরোপুরি পেয়েছি এবং আমি খুশি আমি নতুন কিছু শিখেছি, আপনার উত্তরের সাথে কিছুই ভুল হয়নি, নতুনদের জন্য কিছুটা বিভ্রান্ত হতে পারে ...
হানি

1
এটি কেবল তার জন্যই কাজ করে MySingleton, উদাহরণস্বরূপ MySingleton.mআমি কল করছি[super alloc]
সের্গেই পেট্রুক

6

বরাদ্দ পদ্ধতিতে ওভাররাইট করে ক্লাসটি বরাদ্দ করা যায় তা এড়াতে পারবেন।

@implementation MyClass

static BOOL useinside = NO;
static id _sharedObject = nil;


+(id) alloc {
    if (!useinside) {
        @throw [NSException exceptionWithName:@"Singleton Vialotaion" reason:@"You are violating the singleton class usage. Please call +sharedInstance method" userInfo:nil];
    }
    else {
        return [super alloc];
    }
}

+(id)sharedInstance
{
    static dispatch_once_t p = 0;
    dispatch_once(&p, ^{
        useinside = YES;
        _sharedObject = [[MyClass alloc] init];
        useinside = NO;
    });   
    // returns the same object each time
    return _sharedObject;
}

1
এটি উপরের মন্তব্যে আমার প্রশ্নের উত্তর দেয়। আমি প্রতিরক্ষামূলক প্রোগ্রামিংয়ের জন্য এতটা নই, তবে ...
নিকোলাস মিয়ারি

5

ডেভ ঠিক আছে, পুরোপুরি ঠিক আছে। আপনি চেক আউট করতে চান হতে পারে একটি Singleton তৈরির অ্যাপলের ডক্স অন্যান্য পদ্ধতি কিছু বাস্তবায়ন টিপসের জন্য তা নিশ্চিত করার জন্য শুধুমাত্র একটি কি কখনো তৈরি করা যেতে পারে শ্রেণীর sharedFoo পদ্ধতি ব্যবহার না করে থাকলে।


8
হ ... এটি একটি সিঙ্গলটন তৈরির সবচেয়ে বড় উদাহরণ নয়। মেমরি পরিচালনা পদ্ধতিগুলি ওভাররাইড করা প্রয়োজন হয় না।
ডেভ ডেলং

19
এটি আরসি ব্যবহার করে সম্পূর্ণ অবৈধ।
লোগানকোট্রেল

উদ্ধৃত নথিটি অবসরপ্রাপ্ত হয়েছে। এছাড়াও, যে উত্তরগুলি কেবল বাহ্যিক সামগ্রীর লিঙ্ক হয় তা সাধারণত দুর্বল এসও উত্তর। আপনার উত্তরের মধ্যে ন্যূনতম অংশে প্রাসঙ্গিক অংশ। আপনি উত্তরসূরির জন্য সংরক্ষণ করা পুরানো পথটি না চাইলে এখানে বিরক্ত করবেন না।
টুলবার

4

আপনি যদি নিশ্চিত করতে চান যে [[MyClass বরাদ্দ] init] শেয়ারডইনস্ট্যান্সের মতো একই জিনিসটি ফেরত দিয়েছে (আমার মতে এটি প্রয়োজনীয় নয় তবে কিছু লোকেরা এটি চায়), এটি খুব সহজেই এবং নিরাপদে দ্বিতীয় প্রেরণ_অনসেস ব্যবহার করে করা যেতে পারে:

- (instancetype)init
{
    static dispatch_once_t once;
    static Class *sharedInstance;

    dispatch_once(&once, ^
    {
        // Your normal init code goes here. 
        sharedInstance = self;
    });

    return sharedInstance;
}

এটি [[MyClass বরাদ্দ] init] এবং [মাই ক্লাস শেয়ারড ইনস্ট্যান্স] এর যে কোনও সংমিশ্রণকে একই বস্তুটি ফেরত দিতে দেয়; [মাই ক্লাস শেয়ারড ইনস্ট্যান্স] আরও কিছুটা দক্ষ হবে। এটি কীভাবে কাজ করে: [মাই ক্লাস শেয়ারড ইনস্ট্যান্স] একবার [[মাই ক্লাস বরাদ্দ] init] কল করবে। অন্যান্য কোড এটিকে কল করতে পারে, যে কোনও সময়। প্রথম কলকারী "সাধারণ" সূচনাটি করবে এবং সিঙ্গেলটন অবজেক্টটি আর ডি পদ্ধতিতে সঞ্চিত করবে। আর পরে যে কোনও কল করা বরাদ্দগুলি কীভাবে বরাদ্দ দেয় তা সম্পূর্ণ উপেক্ষা করবে এবং একই ভাগ করা ইনস্ট্যান্স ফিরিয়ে দেবে; বরাদ্দের ফলাফলটি বাতিল করা হবে।

সর্বদা যেমনটি হয়েছে তেমন + শেয়ারডআইনস্ট্যান্স পদ্ধতিটি কাজ করবে। যদি [[MyClass বরাদ্দ] init] কল করার ক্ষেত্রে এটি প্রথম কলার না হয়, তবে আর ডি এর ফলাফল বরাদ্দ কলের ফলাফল নয়, তবে এটি ঠিক।


2

আপনি জিজ্ঞাসা করুন এটি কি "সিঙ্গেলটন তৈরির সর্বোত্তম উপায়" কিনা।

কয়েকটি চিন্তা:

  1. প্রথম, হ্যাঁ, এটি একটি থ্রেড-নিরাপদ সমাধান। এই dispatch_onceপ্যাটার্নটি হ'ল উদ্দেশ্য, সি-তে একক জেনারেট করার জন্য থ্রেড-নিরাপদ উপায়। কোনও উদ্বেগ নেই।

  2. আপনি জিজ্ঞাসা করেছেন, এটি করার জন্য এটি "সেরা" উপায় কিনা। একটি স্বীকৃতি দেওয়া উচিত, যদিও, যে instancetypeএবং[[self alloc] init] সিঙ্গেলনের সাথে একযোগে ব্যবহার সম্ভবত সম্ভাব্য বিভ্রান্তিকর।

    এর সুবিধা instancetype হ'ল এটি ঘোষণার একটি দ্ব্যর্থহীন উপায় যে ক্লাসটি এক ধরণের অবলম্বন না করেই সাবক্ল্যাস করা যেতে পারে id, যেমন আমাদের ইয়েটারিয়ারে করতে হয়েছিল।

    তবে staticএই পদ্ধতিতে সাবক্লাসিং চ্যালেঞ্জ উপস্থাপন করা হয়। কী ImageCacheএবং যদি BlobCacheসিলেটলেটগুলি Cacheতাদের নিজস্ব sharedCacheপদ্ধতি প্রয়োগ না করে সুপারক্লাস থেকে উভয় সাবক্লাস হয় ?

    ImageCache *imageCache = [ImageCache sharedCache];  // fine
    BlobCache *blobCache = [BlobCache sharedCache];     // error; this will return the aforementioned ImageCache!!!

    এটি কাজ করার জন্য, আপনাকে নিশ্চিত করতে হবে সাবক্লাসগুলি তাদের নিজস্ব প্রয়োগ করে sharedInstance (বা যা আপনি এটি নির্দিষ্ট শ্রেণীর জন্য ডাকেন) পদ্ধতিটি ।

    নীচের লাইন, আপনার আসল sharedInstance চেহারাটি দেখে মনে হচ্ছে এটি সাবক্লাস সমর্থন করবে, তবে তা হবে না। আপনি যদি সাবক্লাসিং সমর্থন করতে চান, খুব কমপক্ষে এমন ডকুমেন্টেশন অন্তর্ভুক্ত করুন যা ভবিষ্যতের বিকাশকারীদের সতর্ক করে দেয় যে তাদের অবশ্যই এই পদ্ধতিটিকে ওভাররাইড করতে হবে।

  3. সুইফ্টের সাথে সর্বোত্তম আন্তঃব্যবযোগিতার জন্য আপনি সম্ভবত এটি কোনও শ্রেণি পদ্ধতি নয়, সম্পত্তি হিসাবে সংজ্ঞায়িত করতে চান:

    @interface Foo : NSObject
    @property (class, readonly, strong) Foo *sharedFoo;
    @end

    তারপরে আপনি এগিয়ে গিয়ে এই সম্পত্তিটির জন্য একটি গিটার লিখতে পারেন (প্রয়োগটি dispatch_onceআপনার প্রস্তাবিত প্যাটার্নটি ব্যবহার করবে ):

    + (Foo *)sharedFoo { ... }

    এর সুবিধাটি হ'ল যদি কোনও সুইফ্ট ব্যবহারকারী এটি ব্যবহার করতে যান তবে তারা এমন কিছু করতে চাইবেন:

    let foo = Foo.shared

    দ্রষ্টব্য, নেই () , কারণ আমরা এটিকে সম্পত্তি হিসাবে প্রয়োগ করেছি। সুইফ্ট 3 শুরু করে, এভাবেই সিলেটলেটগুলি সাধারণত অ্যাক্সেস করা হয়। সুতরাং এটি একটি সম্পত্তি হিসাবে সংজ্ঞায়িত করা যে আন্তঃআযোগিতা সহজতর করতে সহায়তা করে।

    একদিকে যেমন, আপনি যদি দেখেন যে অ্যাপল কীভাবে তাদের সিঙ্গলটনের সংজ্ঞা দিচ্ছে, তারা এটি গ্রহণ করেছেন যে প্যাটার্নটি, উদাহরণস্বরূপ তাদের NSURLSessionসিঙ্গলটন নীচে সংজ্ঞায়িত করা হয়েছে:

    @property (class, readonly, strong) NSURLSession *sharedSession;
  4. আরেকটি, খুব গৌণ সুইফট আন্তঃযোগিতা বিবেচনা হ'ল সিঙ্গলটনের নাম। আপনি যদি এর পরিবর্তে প্রকারের নাম অন্তর্ভুক্ত করতে পারেন তবে এটি সর্বোত্তম sharedInstance। উদাহরণস্বরূপ, ক্লাসটি যদি হয় তবে Fooআপনি সিঙ্গলটন সম্পত্তি হিসাবে সংজ্ঞা দিতে পারেন sharedFoo। অথবা ক্লাসটি থাকলে DatabaseManagerআপনি সম্পত্তিটি কল করতে পারেন sharedManager। তারপরে সুইফ্ট ব্যবহারকারীরা এটি করতে পারেন:

    let foo = Foo.shared
    let manager = DatabaseManager.shared

    স্পষ্টতই, আপনি যদি সত্যিই ব্যবহার করতে চান তবে আপনি sharedInstanceযে সুইফট নামটি চান তা সর্বদা ঘোষণা করতে পারেন:

    @property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared);

    স্পষ্টতই, অবজেক্টিভ-সি কোড লেখার সময়, আমাদের সুইফট ইন্টারঅ্যাপেরিবিলিটি অন্য নকশাগুলির বিবেচনার চেয়ে বেশি হওয়া উচিত নয়, তবুও, যদি আমরা কোডটি লিখতে পারি যে উভয় ভাষাকে নিখুঁতভাবে সমর্থন করে, তবে এটি পছন্দনীয়।

  5. আমি অন্যদের সাথে একমত পোষণ করেছি যে আপনি যদি এটি সত্যিকারের সিঙ্গলটন হতে চান যেখানে বিকাশকারীরা তাদের নিজস্ব দৃষ্টান্তগুলি (দুর্ঘটনাক্রমে) তাত্ক্ষণিকভাবে চালু করতে না পারে এবং না করতে পারে, তবে এটি unavailableযোগ্যতা অর্জনকারী initএবং newবুদ্ধিমান।


0

থ্রেড নিরাপদ সিঙ্গলটন তৈরি করতে আপনি এটি করতে পারেন:

@interface SomeManager : NSObject
+ (id)sharedManager;
@end

/* thread safe */
@implementation SomeManager

static id sharedManager = nil;

+ (void)initialize {
    if (self == [SomeManager class]) {
        sharedManager = [[self alloc] init];
    }
}

+ (id)sharedManager {
    return sharedManager;
}
@end

এবং এই ব্লগটি সিঙ্গেলটনকে খুব ভাল ওজেজে / কোকোতে সিঙ্গেলটন ব্যাখ্যা করে


আপনি একটি অতি পুরনো নিবন্ধের সাথে সংযোগ করছেন যখন ওপি সর্বাধিক আধুনিক বাস্তবায়ন সম্পর্কে বৈশিষ্ট্য জিজ্ঞাসা করে।
ভাইকিংগুন্ডো

1
প্রশ্নটি একটি নির্দিষ্ট বাস্তবায়ন সম্পর্কে। আপনি কেবলমাত্র অন্য একটি বাস্তবায়ন পোস্ট করেছেন। আপনার পক্ষে এমনকি প্রশ্নের উত্তর দেওয়ার চেষ্টাও করবেন না।
ভাইকিংগুন্দো

1
@ ভাইকিংগুন্ডো প্রশ্নকারী আবহাওয়া জিজ্ঞাসা করুন থ্রেড নিরাপদ সিঙ্গলটন তৈরির জন্য জিসিডি সবচেয়ে ভাল উপায়, আমার উত্তরটি অন্য পছন্দ দেয় ny কোন ভুল?
হ্যানকক_জু

প্রশ্নকারী যদি জিজ্ঞাসা করে যে কোনও কার্যকর প্রয়োগ থ্রেড-নিরাপদ কিনা। তিনি বিকল্প চাইছেন না।
ভাইকিংগুন্ডো

0
//Create Singleton  
  +( instancetype )defaultDBManager
    {

        static dispatch_once_t onceToken = 0;
        __strong static id _sharedObject = nil;

        dispatch_once(&onceToken, ^{
            _sharedObject = [[self alloc] init];
        });

        return _sharedObject;
    }


//In it method
-(instancetype)init
{
    self = [super init];
  if(self)
     {
   //Do your custom initialization
     }
     return self;
}

0
@interface className : NSObject{
+(className*)SingleTonShare;
}

@implementation className

+(className*)SingleTonShare{

static className* sharedObj = nil;
static dispatch_once_t once = 0;
dispatch_once(&once, ^{

if (sharedObj == nil){
    sharedObj = [[className alloc] init];
}
  });
     return sharedObj;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.