Objective-C - Optimizing this Singleton Pattern?

I found this singleton pattern on the net. It seems to me that he has a lot of things that can be optimized.

-In sharedMySingleton , no need to call persistence? I'm not sure...
-If not, then why is allocWithZone saved?
- what is the use of @synchronized . NSAssert believes that a block can be called many times, so if so, should there be another code to release the previous memory or explicitly exit the block without NSAsserting, and if not, then why is it NSAssert?
- the chain between sharedMySingleton and alloc seems strange. I wrote myself something like:

 +(MySingleton*)sharedMySingleton { @synchronized([MySingleton class]) { if (_sharedMySingleton == nil) _sharedMySingleton = [[self alloc] init]; return _sharedMySingleton; } return nil; } +(id)alloc { @synchronized([MySingleton class]) { return [super alloc]; } return nil; } 

Singleton Template

 #import "MySingleton.h" @implementation MySingleton // ########################################################################################################## // ######################################## SINGLETON PART ################################################## // ########################################################################################################## static MySingleton* _sharedMySingleton = nil; // ================================================================================================= +(MySingleton*)sharedMySingleton // ================================================================================================= { @synchronized([MySingleton class]) { if (_sharedMySingleton == nil) [[self alloc] init]; return _sharedMySingleton; } return nil; } // ================================================================================================= +(id)alloc // ================================================================================================= { @synchronized([MySingleton class]) { NSAssert(_sharedMySingleton == nil, @"Attempted to allocate a second instance of a singleton."); _sharedMySingleton = [super alloc]; return _sharedMySingleton; } return nil; } + (id)allocWithZone:(NSZone *)zone { return [[self sharedMySingleton] retain]; } - (id)copyWithZone:(NSZone *)zone { return self; } - (id)retain { return self; } - (NSUInteger)retainCount { return NSUIntegerMax; /* denotes an object that cannot be released */} - (oneway void)release { /* do nothing */ } - (id)autorelease { return self; } // ########################################################################################################## // ########################################################################################################## // ########################################################################################################## // ================================================================================================= -(id)init // ================================================================================================= { if (!(self = [super init])) return nil; return self; } // ================================================================================================= -(void) dealloc // ================================================================================================= { [super dealloc]; } // ================================================================================================= -(void)test // ================================================================================================= { NSLog(@"Hello World!"); } @end 
+5
source share
3 answers

You should not use this template at all (this is for the special case of Singleton, which you almost never need, and even then you should not use it at all).

There are many good templates. > What does my single Objective-C look like? but most of them are outdated since the release of GCD. On modern versions of Mac and iOS, you should use the following pattern as asked by Colin Barrett in a related question:

 + (MyFoo *)sharedFoo { static dispatch_once_t once; static MyFoo *sharedFoo; dispatch_once(&once, ^{ sharedFoo = [[self alloc] init]; }); return sharedFoo; } 

I just copy it here, and not marking a duplicate question, because the old answers to the highest questions are outdated.

+17
source

There is no need to call retain because there is alloc . Calling retain on top of this will result in a memory leak. On allocWithZone , the value is stored because it is singleton, so we do not want to create two different instances of the class. Rather, highlighting the new instance, we increase the number of remaining singleton instances. Why is this? It is likely that someone would not know about the singleton type of the class. If he calls allocWithZone and then frees the instance, everything will work fine, and he actually accessed the singleton single instance.

@synchronized used to prevent two calls from two different threads from entering the if statement simultaneously. Thus, the code is thread safe.

NSSAssert is likely to make a crash application if two singleton instances are created. This is โ€œjust for confidenceโ€ code, also called defensive programming.

As for the chain between sharedMySingleton and alloc , I think this is normal.

0
source

In the sharedMySingleton method there is no need to call persistence?

alloc returns a new instance with reference counting, so saving is not required.

If not, why is there a persistence in allocWithZone?

According to the rules, when you call allocWithZone , you own the link, so allocWithZone significantly increase the reference count for you. But this implementation of allocWithZone returns an instance of a singleton that has already been created and belongs to someone else (the sharedMySingleton method). Thus, the sharedMySingleton method creates an object with alloc , so it becomes the owner. And then you get the same instance through allocWithZone , so you become the second owner of the same instance. Thus, the conservation account should increase, because now there are two owners. This is why allocWithZone needs to be saved.

What is @synchronized?

@synchronized allows code to be invoked simultaneously by multiple threads. If you never call sharedMySingleton from more than one thread, then this is not necessary, and you can omit it.

NSAssert believes that a block can be called many times, so if so, there should be one more code to release the previous memory, or it can be clearly seen that without NSAsserting, and if not, then why is there this NSAssert?

Since the class is designed for singleton, alloc should only be called once. NSAssert() terminates the program if alloc is called more than once. Because NSAssert() terminates the program when alloc is called a second time, memory management is not required.

0
source

Source: https://habr.com/ru/post/917183/


All Articles