source

ARC와 호환되는 Objective-C 싱글톤을 구현하려면 어떻게 해야 하나요?

nicesource 2023. 4. 24. 23:28
반응형

ARC와 호환되는 Objective-C 싱글톤을 구현하려면 어떻게 해야 하나요?

Xcode 4.2에서 자동 참조 카운트(ARC)를 사용할 때 컴파일 및 동작이 올바른 싱글톤 클래스를 변환(또는 작성)하려면 어떻게 해야 합니까?

이미 하고 있는 것과 같은 방법으로, 다음과 같이 합니다.

+ (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;
}

needed.do 로서 다른 인스턴스를 작성하는 경우는, 다음의 순서에 따릅니다.

+ (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;
}

이것은 ARC 및 비 ARC용 버전입니다.

사용방법:

MySingletonClass.h

@interface MySingletonClass : NSObject

+(MySingletonClass *)sharedInstance;

@end

MySingletonClass.m

#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end

이것은 ARC 아래에 있는 나의 패턴이다.GCD를 사용하여 새로운 패턴을 만족시키고, Apple의 오래된 인스턴스화 방지 패턴도 만족시킵니다.

@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

이 답을 읽고 다른 답을 읽어보세요.

싱글톤이 무엇을 의미하는지, 그리고 싱글톤이 무엇을 필요로 하는지, 만약 이해하지 못한다면 해결책을 전혀 이해하지 못할 것입니다.

싱글톤을 정상적으로 작성하려면 다음 3가지 작업을 수행할 수 있어야 합니다.

  • 경합 조건이 있는 경우 SharedInstance의 여러 인스턴스를 동시에 생성할 수 없습니다.
  • 여러 호출 간에 값을 기억하고 유지합니다.
  • 한 번만 생성해 주세요.진입점을 제어함으로써.

dispatch_once_t는 블록을 1회만 디스패치함으로써 레이스 조건을 해결하는 데 도움이 됩니다.

Static 를 사용하면 호출 수에 관계없이 그 가치를 "기억"할 수 있습니다.어떻게 기억하죠?sharedInstance의 정확한 이름을 가진 새 인스턴스를 다시 생성할 수 없습니다. 원래 생성된 인스턴스와 함께 작동합니다.

호출 사용 안 함alloc init(즉, 우리는 아직alloc init메서드는 NSObject 서브클래스이기 때문에 sharedInstance 클래스에서는 사용하지 않는 것이 좋습니다만, 이것을 실현하려면 ,+(instancetype)sharedInstance여러 스레드에서 동시에 여러 번 시도하더라도 한 번만 시작하도록 제한되며 값을 기억합니다.

코코아 자체와 함께 제공되는 가장 일반적인 시스템 중 일부는 다음과 같습니다.

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

기본적으로 중앙 집중식 효과를 필요로 하는 모든 것은 일종의 싱글톤 디자인 패턴을 따라야 합니다.

또는 Objective-C는 NSObject 및 모든 서브클래스에 +(void) 초기화 방법을 제공합니다.항상 클래스의 메서드 앞에 호출됩니다.

iOS6에서 한번 브레이크 포인트를 설정하고 스택 프레임에 한번 dispatch_one이 표시되었습니다.

Singleton Class : 어떤 경우에도 여러 클래스의 개체를 만들 수 없습니다.

+ (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. init 메서드에서 sharedInstance 메서드가 다시 호출되면(예를 들어 싱글톤을 사용하는 다른 오브젝트가 거기에서 구축되기 때문에) 스택오버플로우가 발생합니다.
  2. 클래스 계층의 경우 계층 내 구체적인 클래스별로 싱글톤이 1개(sharedInstance 메서드가 호출된 계층의 첫 번째 클래스)가 아닌 싱글톤만 존재합니다.

다음 코드는 이 두 가지 문제를 모두 해결합니다.

+ (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;
}
#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

위의 코드가 도움이 되길 바랍니다.

싱글톤을 빨리 만들어야 한다면

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

언급URL : https://stackoverflow.com/questions/7568935/how-do-i-implement-an-objective-c-singleton-that-is-compatible-with-arc

반응형