Giter VIP home page Giter VIP logo

objective-c-optimized-singleton's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

objective-c-optimized-singleton's Issues

Slight modifications to the .m file to avoid compile errors with latest clang compiler related to volatile

In order not to have Clang's compiler (LLVM clang not LLVM-GCC) complain about this singleton utility in its latest releases (Xcode 4.1 and Xcode 4.2), I have to make some small changes to the source code:

(I had to add volatile to many instances in which a reference to the singleton object was returned)

//
// SynthesizeSingleton.h
//
// Modified by Karl Stenerud starting 16/04/2010.
// - Moved the swizzle code to allocWithZone so that non-default init methods may be
// used to initialize the singleton.
// - Added "lesser" singleton which allows other instances besides sharedInstance to be created.
// - Added guard ifndef so that this file can be used in multiple library distributions.
// - Made singleton variable name class-specific so that it can be used on multiple classes
// within the same compilation module.
//
// Modified by CJ Hanson on 26/02/2010.
// This version of Matt's code uses method_setImplementaiton() to dynamically
// replace the +sharedInstance method with one that does not use @synchronized
//
// Based on code by Matt Gallagher from CocoaWithLove
//
// Created by Matt Gallagher on 20/10/08.
// Copyright 2009 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file without charge in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//

ifndef SYNTHESIZE_SINGLETON_FOR_CLASS

import <objc/runtime.h>

pragma mark -

pragma mark Singleton

/* Synthesize Singleton For Class
*

  • Creates a singleton interface for the specified class with the following methods:
    *
  • + (MyClass*) sharedInstance;
  • + (void) purgeSharedInstance;
    *
  • Calling sharedInstance will instantiate the class and swizzle some methods to ensure
  • that only a single instance ever exists.
  • Calling purgeSharedInstance will destroy the shared instance and return the swizzled
  • methods to their former selves.
    *
  • Usage:
    *
  • MyClass.h:
  • ========================================
  • #import "SynthesizeSingleton.h"
  • @interface MyClass: SomeSuperclass
  • {
  •  ...
    
  • }
  • SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(MyClass);
  • @EnD
  • ========================================
    *
    *
  • MyClass.m:
  • ========================================
  • #import "MyClass.h"
  • // This line is optional. Use it if you've enabled GCC_WARN_UNDECLARED_SELECTOR
  • SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(MyClass);
  • SYNTHESIZE_SINGLETON_FOR_CLASS(MyClass);
  • ...
  • @EnD
  • ========================================
    *
    *
  • Note: Calling alloc manually will also initialize the singleton, so you
  • can call a more complex init routine to initialize the singleton like so:
    *
  • [[MyClass alloc] initWithParam:firstParam secondParam:secondParam];
    *
  • Just be sure to make such a call BEFORE you call "sharedInstance" in
  • your program.
    */

define SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(SS_CLASSNAME) \

\

  • (SS_CLASSNAME*) sharedInstance; \
  • (void) purgeSharedInstance;

define SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(SS_CLASSNAME) \

@interface SS_CLASSNAME (SynthesizeSingletonPrivate) \

  • (NSUInteger)retainCountDoNothing; \
  • (NSUInteger)retainCountDoSomething; \
  • (void)releaseDoNothing; \
  • (void)releaseDoSomething; \
  • (id)autoreleaseDoNothing; \
  • (id)autoreleaseDoSomething;
    @EnD

define SYNTHESIZE_SINGLETON_FOR_CLASS(SS_CLASSNAME) \


static volatile SS_CLASSNAME* _##SS_CLASSNAME##_sharedInstance = nil;
\

  • (volatile SS_CLASSNAME_) sharedInstanceNoSynch
    {
    return (volatile SS_CLASSNAME_) _##SS_CLASSNAME##_sharedInstance;
    }
    \
  • (volatile SS_CLASSNAME_) sharedInstanceSynch
    {
    @synchronized(self)
    {
    if(nil == _##SS_CLASSNAME##_sharedInstance)
    {
    _##SS_CLASSNAME##sharedInstance = [[self alloc] init];
    }
    }
    return (volatile SS_CLASSNAME
    ) _##SS_CLASSNAME##_sharedInstance;
    }
    \
  • (volatile SS_CLASSNAME_) sharedInstance
    {
    return (volatile SS_CLASSNAME_)[self sharedInstanceSynch];
    }
    \
  • (id)allocWithZone:(NSZone*) zone
    {
    @synchronized(self)
    {
    if (nil == _##SS_CLASSNAME##_sharedInstance)
    {
    _##SS_CLASSNAME##_sharedInstance = [super allocWithZone:zone];
    if(nil != _##SS_CLASSNAME##_sharedInstance)
    {
    Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch));
    method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod));
    method_setImplementation(class_getInstanceMethod(self, @selector(retainCount)), class_getMethodImplementation(self, @selector(retainCountDoNothing)));
    method_setImplementation(class_getInstanceMethod(self, @selector(release)), class_getMethodImplementation(self, @selector(releaseDoNothing)));
    method_setImplementation(class_getInstanceMethod(self, @selector(autorelease)), class_getMethodImplementation(self, @selector(autoreleaseDoNothing)));
    }
    }
    }
    return _##SS_CLASSNAME##_sharedInstance;
    }
    \
  • (void)purgeSharedInstance
    {
    @synchronized(self)
    {
    if(nil != _##SS_CLASSNAME##sharedInstance)
    {
    Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceSynch));
    method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod));
    method_setImplementation(class_getInstanceMethod(self, @selector(retainCount)), class_getMethodImplementation(self, @selector(retainCountDoSomething)));
    method_setImplementation(class_getInstanceMethod(self, @selector(release)), class_getMethodImplementation(self, @selector(releaseDoSomething)));
    method_setImplementation(class_getInstanceMethod(self, @selector(autorelease)), class_getMethodImplementation(self, @selector(autoreleaseDoSomething)));
    [
    ##SS_CLASSNAME##_sharedInstance release];
    _##SS_CLASSNAME##_sharedInstance = nil;
    }
    }
    }
    \
  • (id)copyWithZone:(NSZone *)zone
    {
    return self;
    }
    \
  • (id)retain
    {
    return self;
    }
    \
  • (NSUInteger)retainCount
    {
    NSAssert1(1==0, @"SynthesizeSingleton: %@ ERROR: -(NSUInteger)retainCount method did not get swizzled.", self);
    return NSUIntegerMax;
    }
    \
  • (NSUInteger)retainCountDoNothing
    {
    return NSUIntegerMax;
    } \
  • (NSUInteger)retainCountDoSomething
    {
    return [super retainCount];
    }
    \
  • (oneway void)release
    {
    NSAssert1(1==0, @"SynthesizeSingleton: %@ ERROR: -(void)release method did not get swizzled.", self);
    }
    \
  • (void)releaseDoNothing{}
    \
  • (void)releaseDoSomething
    {
    @synchronized(self)
    {
    [super release];
    }
    }
    \
  • (id)autorelease
    {
    NSAssert1(1==0, @"SynthesizeSingleton: %@ ERROR: -(id)autorelease method did not get swizzled.", self);
    return self;
    }
    \
  • (id)autoreleaseDoNothing
    {
    return self;
    }
    \
  • (id)autoreleaseDoSomething
    {
    return [super autorelease];
    }

pragma mark -

pragma mark Lesser Singleton

/* A lesser singleton has a shared instance, but can also be instantiated on its own.
*

  • For a lesser singleton, you still use SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(),
  • but use SYNTHESIZE_LESSER_SINGLETON_FOR_CLASS() in the implementation file.
  • You must specify which creation methods are to initialize the shared instance
  • (besides "sharedInstance") via CALL_LESSER_SINGLETON_INIT_METHOD()
    *
  • Example:
    *
  • MyClass.h:
  • ========================================
  • #import "SynthesizeSingleton.h"
  • @interface MyClass: SomeSuperclass
  • {
  •  int value;
    
  •  ...
    
  • }
  • SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(MyClass);
    • (void) initSharedInstanceWithValue:(int) value;
  • - (id) initWithValue:(int) value;
    *
  • @EnD
  • ========================================
    *
    *
  • MyClass.m:
  • ========================================
  • #import "MyClass.h"
  • // This line is optional. Use it if you've enabled GCC_WARN_UNDECLARED_SELECTOR
  • SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(MyClass);
  • SYNTHESIZE_LESSER_SINGLETON_FOR_CLASS(MyClass);
    • (void) initSharedInstanceWithValue:(int) value
  • {
  •  CALL_LESSER_SINGLETON_INIT_METHOD(MyClass, initWithValue:value);
    
  • }
  • ...
  • @EnD
  • ========================================
    *
    *
  • Note: CALL_LESSER_SINGLETON_INIT_METHOD() will not work if your
  • init call contains commas. If you need commas (such as for varargs),
  • or other more complex initialization, use the PRE and POST macros:
    *
    • (void) initSharedInstanceComplex
  • {
  •  CALL_LESSER_SINGLETON_INIT_METHOD_PRE(MyClass);
    
  •  int firstNumber = [self getFirstNumberSomehow];
    
  •  _sharedInstance = [[self alloc] initWithValues:firstNumber, 2, 3, 4, -1];
    
  •  CALL_LESSER_SINGLETON_INIT_METHOD_POST(MyClass);
    
  • }
    */

define SYNTHESIZE_LESSER_SINGLETON_FOR_CLASS(SS_CLASSNAME) \


static volatile SS_CLASSNAME* _##SS_CLASSNAME##_sharedInstance = nil;
\

  • (SS_CLASSNAME_) sharedInstanceNoSynch
    {
    return (SS_CLASSNAME_) _##SS_CLASSNAME##_sharedInstance;
    }
    \
  • (SS_CLASSNAME_) sharedInstanceSynch
    {
    @synchronized(self)
    {
    if(nil == _##SS_CLASSNAME##_sharedInstance)
    {
    _##SS_CLASSNAME##sharedInstance = [[self alloc] init];
    if(
    ##SS_CLASSNAME##sharedInstance)
    {
    Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch));
    method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod));
    }
    }
    }
    return (SS_CLASSNAME
    ) _##SS_CLASSNAME##_sharedInstance;
    }
    \
  • (volatile SS_CLASSNAME_)sharedInstance
    {
    return (volatile SS_CLASSNAME_) [self sharedInstanceSynch];
    }
    \
  • (void)purgeSharedInstance
    {
    @synchronized(self)
    {
    Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceSynch));
    method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod));
    [_##SS_CLASSNAME##_sharedInstance release];
    _##SS_CLASSNAME##_sharedInstance = nil;
    }
    }

define CALL_LESSER_SINGLETON_INIT_METHOD_PRE(SS_CLASSNAME) \

@synchronized(self)
{
if(nil == _##SS_CLASSNAME##_sharedInstance)
{

define CALL_LESSER_SINGLETON_INIT_METHOD_POST(SS_CLASSNAME) \

if(_##SS_CLASSNAME##_sharedInstance)
{
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch));
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod));
}
}
}

define CALL_LESSER_SINGLETON_INIT_METHOD(SS_CLASSNAME,INIT_CALL) \

CALL_LESSER_SINGLETON_INIT_METHOD_PRE(SS_CLASSNAME);
_##SS_CLASSNAME##_sharedInstance = [[self alloc] INIT_CALL];
CALL_LESSER_SINGLETON_INIT_METHOD_POST(SS_CLASSNAME)

endif /* SYNTHESIZE_SINGLETON_FOR_CLASS */

How does this compare to the dispatch_once approach?

I’ve seen elsewhere implementations of a singleton that use dispatch_once to initialize the static variable.
How does that compare with the method swizzling approach, and, can they be combined, or there is no point?

TIA
Victor

Why not use +(void)initialize?

+initialize is guaranteed to be called from inside the Objective-C runtime lock the first time the target class receives a message.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.