আমি কীভাবে একটি ওজেক্টিভ-সি সিঙ্গলটন প্রয়োগ করব যা এআরসি সাথে সামঞ্জস্যপূর্ণ?


172

এক্সকোড ৪.২-এ স্বয়ংক্রিয় রেফারেন্স গণনা (এআরসি) ব্যবহার করার সময় আমি কীভাবে একটি সিঙ্গলটন শ্রেণি রূপান্তর (বা তৈরি) করব যা সঠিকভাবে সংকলন করে এবং আচরণ করে?


1
আমি সম্প্রতি ম্যাট গ্যাল্লোয়ের একটি নিবন্ধ পেয়েছি যা এআরসি এবং ম্যানুয়াল মেমরি ম্যানেজমেন্ট উভয় পরিবেশের জন্য সিঙ্গলটনের উপর গভীরতার সাথে চলছে। galloway.me.uk/tutorials/singleton-classes
cescofry

উত্তর:


391

আপনি যেভাবে ইতিমধ্যে এটি করা উচিত ঠিক ঠিক তেমনভাবে:

+ (instancetype)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

9
আপনি শুধু মেমরি ব্যবস্থাপনা শাস্তা দামের আইসক্রীম কোন না অ্যাপল মধ্যে সুপারিশ করতে ব্যবহৃত developer.apple.com/library/mac/documentation/Cocoa/Conceptual/...
ক্রিস্টোফার Pickslay

1
@ মেকিংসায়েন্সফিকশন ফ্যাক্ট, আপনি এই পোস্টটি
কার্ভিচ

6
staticএকটি পদ্ধতি / ফাংশনের মধ্যে ঘোষিত ডেভিড ভেরিয়েবলগুলি কোনও পদ্ধতি / ফাংশনের staticবাইরে ঘোষিত ভেরিয়েবলের সমান , তারা কেবল সেই পদ্ধতি / ফাংশনের ক্ষেত্রের মধ্যে বৈধ। +sharedInstanceপদ্ধতির মাধ্যমে প্রতিটি পৃথক রান (এমনকি বিভিন্ন থ্রেডেও) একই sharedInstanceপরিবর্তনশীলটিকে 'দেখবে' ।
নিক

9
কেউ যদি [[MyClass বরাদ্দ] init] কল করে তবে কি হবে? এটি একটি নতুন অবজেক্ট তৈরি করবে। কীভাবে আমরা এড়াতে পারি (পদ্ধতির বাইরে স্ট্যাটিক মাইক্লাস * শেয়ারডইনস্টান্স = শূন্য ঘোষণার বাইরে)।
রিকার্ডো সানচেজ-সায়েজ

2
যদি অন্য কোনও প্রোগ্রামার বিড়বিড় হয় এবং যখন তাদের ভাগ করা ইনস্ট্যান্স বা অনুরূপ বলা উচিত ছিল তখন ডিকে কল করে, এটি তাদের ত্রুটি। অন্যকে সম্ভাব্য ভুল করা বন্ধ করার জন্য ভাষার মৌলিক এবং মৌলিক চুক্তিগুলি সরিয়ে দেওয়া বেশ ভুল বলে মনে হচ্ছে। আরো আলোচনা সভায় আছে boredzo.org/blog/archives/2009-06-17/doing-it-wrong
occulus

8

আপনি যদি প্রয়োজন মতো অন্য উদাহরণ তৈরি করতে চান তবে এটি করুন:

+ (MyClass *)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

অন্যথায়, আপনার এটি করা উচিত:

+ (id)allocWithZone:(NSZone *)zone
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}

1
সত্য / মিথ্যা: dispatch_once()বিটের অর্থ এই যে আপনি অতিরিক্ত উদাহরণগুলি পাবেন না, এমনকি প্রথম উদাহরণেও ...?
অলি

4
@ অলি: ভুয়া, কারণ ক্লায়েন্ট কোড অ্যাক্সেসটিকে [[MyClass alloc] init]বাইপাস করতে পারে এবং করতে পারে sharedInstance। দংএক্সু, আপনার পিটার হোসে সিঙ্গলটন নিবন্ধটি দেখতে হবে । যদি আপনি allocWithZone:আরও উদাহরণগুলি তৈরি হওয়া থেকে রোধ করতে ওভাররাইড করতে চলেছেন , initতবে ভাগ করা দৃষ্টান্তটি পুনরায় আরম্ভ হতে বাধা দেওয়ার জন্য আপনার ওভাররাইড করা উচিত ।
jscs

ঠিক আছে, আমি যা ভেবেছিলাম তাই allocWithZone:সংস্করণ the ধন্যবাদ.
অলি

2
এটি বরাদ্দ উইথজোনের চুক্তিটি পুরোপুরি ভঙ্গ করে।
আকস্মিক

1
সিঙ্গেলনের অর্থ "যেকোন সময় স্মৃতিতে কেবল একটি বস্তু", এটি একটি জিনিস, পুনরায় আরম্ভ করা অন্য জিনিস thing
দংএক্সু


2

এটিআরসি এর অধীনে আমার প্যাটার্ন। জিসিডি ব্যবহার করে নতুন প্যাটার্নটি সন্তুষ্ট করে এবং অ্যাপলের পুরানো তাত্পর্য প্রতিরোধের প্যাটার্নটিকেও সন্তুষ্ট করে।

@implementation AAA
+ (id)alloc
{
    return  [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
    [self doesNotRecognizeSelector:_cmd];
    abort();
}
+ (instancetype)theController
{
    static AAA* c1  =   nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        c1  =   [[super allocWithZone:nil] init];

        // For confirm...       
        NSLog(@"%@", NSStringFromClass([c1 class]));    //  Prints AAA
        NSLog(@"%@", @([c1 class] == self));            //  Prints 1

        Class   real_superclass_obj =   class_getSuperclass(self);
        NSLog(@"%@", @(real_superclass_obj == self));   //  Prints 0
    });

    return  c1;
}
@end

1
এর ফলাফলটি কি সুপারক্লাসের c1উদাহরণ হতে পারে না AAA? আপনাকে কল +allocকরা দরকার self, চালু নয় super
নিক ফরজ

@ নিকফর্জ superমানে সুপার-ক্লাসের অবজেক্ট নয়। আপনি উচ্চ-শ্রেণীর অবজেক্টটি পেতে পারেন না এটির অর্থ কেবল মেশিনগুলি পদ্ধতির অতি-শ্রেণীর সংস্করণে পাঠানো। superএখনও selfক্লাস পয়েন্ট । আপনি যদি সুপার-ক্লাসের অবজেক্ট পেতে চান তবে আপনার রানটাইম রিফ্লেকশন ফাংশনগুলি নেওয়া দরকার।
eonil

@ নিকফর্জি এবং -allocWithZone:পদ্ধতিটি ওভাররাইডিং পয়েন্ট অফার করার জন্য রানটাইমের বরাদ্দকরণের কার্যকারিতাটির জন্য একটি সহজ চেইন। সুতরাং শেষ পর্যন্ত, selfপয়েন্টার == বর্তমান শ্রেণি অবজেক্ট বরাদ্দকারীর কাছে পাঠানো হবে এবং শেষ অবধি AAAউদাহরণ বরাদ্দ করা হবে।
eonil

আপনি সঠিক, আমি superশ্রেণি পদ্ধতিতে কীভাবে কাজ করে তার সূক্ষ্মতাগুলি ভুলে গিয়েছিলাম ।
নিক ফরজ

# ইম্পোর্ট <জেজক / আপত্তি / রানটাইম.h> ব্যবহার করতে মনে রাখবেন
রায়ান হিটনার

2

এই উত্তরটি পড়ুন এবং তারপরে যান এবং অন্য উত্তরটি পড়ুন।

আপনার অবশ্যই প্রথম জানা উচিত যে একটি সিঙ্গলটনের অর্থ কী এবং এর প্রয়োজনীয়তাগুলি কী, যদি আপনি এটি বুঝতে না পারেন, তার চেয়ে আপনি সমাধানটি বুঝতে পারবেন না - মোটেও!

একটি সিঙ্গলটন সফলভাবে তৈরি করতে আপনাকে নিম্নলিখিত 3 টি করতে সক্ষম হবেন:

  • যদি কোনও রেসের শর্ত ছিল , তবে আমাদের অবশ্যই আপনার SharedInstance এর একাধিক দৃষ্টান্ত একই সাথে তৈরি করার অনুমতি দেব না!
  • একাধিক আমন্ত্রণের মধ্যে মানটি মনে রাখবেন এবং রাখুন।
  • এটি একবার তৈরি করুন। প্রবেশের স্থানটি নিয়ন্ত্রণ করে

dispatch_once_tআপনাকে কেবলমাত্র একবার এর ব্লকটি একবার প্রেরণের অনুমতি দিয়ে দৌড়ের অবস্থার সমাধান করতে সহায়তা করে ।

Staticআপনাকে অনুরোধের যে কোনও সংখ্যা জুড়ে এর মানটিকে "মনে রাখতে" সহায়তা করে। এটা কিভাবে মনে আছে? এটি আপনার শেয়ারডইনস্ট্যান্সের সেই সঠিক নামটি দিয়ে আর কোনও নতুন উদাহরণ তৈরি করার অনুমতি দেয় না এটি কেবল যেটি তৈরি হয়েছিল তার সাথে কাজ করে।

কল করা ব্যবহার না করাalloc init (যেমন আমাদের এখনও alloc initপদ্ধতি রয়েছে যেহেতু আমরা একটি এনএসবজেক্ট সাবক্লাস, যদিও আমাদের সেগুলি ব্যবহার করা উচিত নয়), আমরা এটি ব্যবহার করে অর্জন করি +(instancetype)sharedInstance, যা কেবল একবারে শুরু করার জন্য আবদ্ধ , বিভিন্ন থ্রেডের একাধিক প্রচেষ্টা নির্বিশেষে একই সাথে এবং এর মান মনে রাখবেন।

কিছু সাধারণ সিস্টেমে সিলেটলেটগুলি যা নিজেই কোকো নিয়ে আসে:

  • [UIApplication sharedApplication]
  • [NSUserDefaults standardUserDefaults]
  • [NSFileManager defaultManager]
  • [NSBundle mainBundle]
  • [NSOperations mainQueue]
  • [NSNotificationCenter defaultCenter]

মূলত যে কোনও কিছু কেন্দ্রিক প্রভাব ফেলতে হবে তার জন্য কোনও একক সিঙ্গলটন ডিজাইনের ধরণ অনুসরণ করতে হবে।


1

বিকল্পভাবে, অবজেক্টিভ-সি এনএসবজেক্ট এবং এর সমস্ত উপ-শ্রেণীর জন্য + (শূন্য) আরম্ভের পদ্ধতি সরবরাহ করে। এটি সর্বদা ক্লাসের যে কোনও পদ্ধতির আগে ডাকা হয়।

আমি আইওএস 6-এ একবারে একটি ব্রেকপয়েন্ট স্থাপন করেছি এবং স্ট্যাচ ফ্রেমে ডিসপ্যাচ_অনসেস উপস্থিত হয়েছিল।


0

সিঙ্গলটন ক্লাস: কেউ কোনও ক্ষেত্রে বা যে কোনও উপায়ে ক্লাসের একাধিক অবজেক্ট তৈরি করতে পারে না।

+ (instancetype)sharedInstance
{
    static ClassName *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[ClassName alloc] init];
        // Perform other initialisation...
    });
    return sharedInstance;
}
//    You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only. 

-(MyClass)init
{
   return [ClassName sharedInstance];
}

1
কেউ যদি ডিআর কল করে, দীক্ষা কল করবে শেয়ারডআইনস্ট্যান্স, শেয়ারডইনস্ট্যান্স টিআর কল করবে, আরআর দ্বিতীয় বার শেয়ারডইনস্ট্যান্স কল করবে, তারপরে ক্রাশ হবে! প্রথমত, এটি একটি অসীম পুনরাবৃত্তি লুপ। দ্বিতীয়ত, ডিসপ্যাচ_নসে কল করার দ্বিতীয় পুনরাবৃত্তি ক্রাশ হবে কারণ এটি প্রেরণ_অনসেস থেকে আবার কল করা যায় না।
চক ক্রুটসিংগার

0

স্বীকৃত উত্তরের সাথে দুটি বিষয় রয়েছে, যা আপনার উদ্দেশ্যে প্রাসঙ্গিক হতে পারে বা নাও হতে পারে।

  1. ডিআর পদ্ধতি থেকে যদি কোনওভাবে শেয়ারডআইনস্ট্যান্স পদ্ধতিটিকে আবার ডাকা হয় (উদাহরণস্বরূপ যেহেতু অন্যান্য বস্তুগুলি সেখান থেকে তৈরি করা হয় যা সিঙ্গলটন ব্যবহার করে) এটি স্ট্যাকের উপচে পড়বে cause
  2. শ্রেণিবিন্যাসের জন্য শ্রেণিবিন্যাসে কংক্রিটের প্রতি একক সিঙ্গলটনের পরিবর্তে কেবলমাত্র একটি সিঙ্গলটন রয়েছে (যথা: ভাগ্যক্রমের প্রথম শ্রেণি, যার উপরে ভাগ করে নেওয়া পদ্ধতিটি বলা হত), পরিবর্তে শ্রেণিবদ্ধ প্রতিটি কংক্রিট শ্রেণীর পরিবর্তে single

নিম্নলিখিত কোড এই উভয় সমস্যার যত্ন নেয়:

+ (instancetype)sharedInstance {
    static id mutex = nil;
    static NSMutableDictionary *instances = nil;

    //Initialize the mutex and instances dictionary in a thread safe manner
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mutex = [NSObject new];
        instances = [NSMutableDictionary new];
    });

    id instance = nil;

    //Now synchronize on the mutex
    //Note: do not synchronize on self, since self may differ depending on which class this method is called on
    @synchronized(mutex) {
        id <NSCopying> key = (id <NSCopying>)self;
        instance = instances[key];
        if (instance == nil) {
            //Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
            id allocatedInstance = [self alloc];

            //Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
            //Do this right after allocation to avoid the stackoverflow problem
            if (allocatedInstance != nil) {
                instances[key] = allocatedInstance;
            }
            instance = [allocatedInstance init];

            //Following code may be overly cautious
            if (instance != allocatedInstance) {
                //Somehow the init method did not return the same instance as the alloc method
                if (instance == nil) {
                    //If init returns nil: immediately remove the instance again
                    [instances removeObjectForKey:key];
                } else {
                    //Else: put the instance in the dictionary instead of the allocatedInstance
                    instances[key] = instance;
                }
            }
        }
    }
    return instance;
}

-2
#import <Foundation/Foundation.h>

@interface SingleTon : NSObject

@property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;

@end

#import "SingleTon.h"
@implementation SingleTon

+(SingleTon *) theSingleTon{
    static SingleTon *theSingleTon = nil;

    if (!theSingleTon) {

        theSingleTon = [[super allocWithZone:nil] init
                     ];
    }
    return theSingleTon;
}

+(id)allocWithZone:(struct _NSZone *)zone{

    return [self theSingleTon];
}

-(id)init{

    self = [super init];
    if (self) {
        // Set Variables
        _name = @"Kiran";
    }

    return self;
}

@end

আশা করি উপরের কোডটি এতে সহায়তা করবে।


-2

যদি আপনার দ্রুত সিঙ্গেলটন তৈরি করতে হয়,

class var sharedInstance: MyClass {
    struct Singleton {
        static let instance = MyClass()
    }
    return Singleton.instance
}

অথবা

struct Singleton {
    static let sharedInstance = MyClass()
}

class var sharedInstance: MyClass {
    return Singleton.sharedInstance
}

আপনি এইভাবে ব্যবহার করতে পারেন

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