Get the true responder to an ObjC method when it is being forwarded - objective-c

I came across a case where a UITableView/UICollectionView delegate is being forwarded by a proxy object (not an NSProxy, just a regular object).
Depending on the specific delegate method, the proxy will forward it to one of 2 objects which will actually respond to the method.
Given a delegate callback, I would like to know the "true" instance which is responding to the method call.
The proxy code looks like:
#implementation DelegateSplitter
- (instancetype)initWithFirstDelegate:(id<NSObject>)firstDelegate secondDelegate:(id<NSObject>)secondDelegate
{
if(self = [super init])
{
_firstDelegate = firstDelegate;
_secondDelegate = secondDelegate;
}
return self;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
SEL aSelector = [anInvocation selector];
if([self.firstDelegate respondsToSelector:aSelector])
{
[anInvocation invokeWithTarget:self.firstDelegate];
}
if([self.secondDelegate respondsToSelector:aSelector])
{
[anInvocation invokeWithTarget:self.secondDelegate];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *first = [(NSObject *)self.firstDelegate methodSignatureForSelector:aSelector];
NSMethodSignature *second = [(NSObject *)self.secondDelegate methodSignatureForSelector:aSelector];
if(first)
{
return first;
}
else if(second)
{
return second;
}
return nil;
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if([self.firstDelegate respondsToSelector:aSelector] || [self.secondDelegate respondsToSelector:aSelector])
{
return YES;
}
else
{
return NO;
}
}
#end
My code looks like:
Given a delegate method I want to know which instance is responding:
// delegate is an instance of DelegateSplitter
id <UITableViewDelegate> delegate = tv.delegate;
SEL didSelectItemSelector = #selector(collectionView:didSelectItemAtIndexPath:);
if ([delegate respondsToSelector:didSelectItemSelector]) {
// the delegate splitter doesn't forward the call
...
return;
}
// the delegate (proxy) forwards the method to a different instance
if (![delegate.class instancesRespondToSelector:didSelectItemSelector]) {
// the delegate responds to selector but the class instances themselves do not respond to the selector. This is possible if the delegate is forwarding all invocations to a different object
NSObject *d = (NSObject *)delegate;
NSMethodSignature *ms = [d methodSignatureForSelector:didSelectItemSelector];
if (ms) {
** I WANT TO GET THE INSTANCE WHICH IS RESPONDING**
????
HOW DO I GET IT
?????
}
}
EDIT:
Current hack in place (would like something more holistic):
Make the forwarder invoke on a mock object and take the target object
#implementation NSObject (HACK)
- (id)responderToSelector:(SEL)selector
{
if ([self respondsToSelector:selector] && [self.class instancesRespondToSelector:selector]) {
return self; // the class and the instance actually will respond to the selector when called
}
if ([self respondsToSelector:selector]) {
// invocations are forwarded
id forward = [self forwardingTargetForSelector:selector];
if (forward && forward != self) {
return [forward responderToSelector:selector];
}
NSMethodSignature *ms = [self methodSignatureForSelector:selector];
if (ms) {
MockInvocation *mockInvocation = [MockInvocation invocationWithMethodSignature:ms];
mockInvocation.selector = selector;
[self forwardInvocation:mockInvocation];
return mockInvocation.target ?: mockInvocation.innerTarget;
}
}
return nil;
}
#interface MockInvocation : NSInvocation
#property (nonatomic, weak) id innerTarget;
#end
#implementation IIOMockInvocation
- (void)invoke
{
}
- (void)invokeWithTarget:(id)target
{
_innerTarget = target;
}
#end

Related

EXC_BAD_ACCESS when invoke an NSInvocation of an argument as NSNumber

I have a class called "MyUploadClient" for handling video upload task. "MyUploadClient" has a protocol called "MyUploadClientDelegate". Someone use "MyUploadClient" to upload video needs to comfort to this protocol, and the delegate may be more than one, so I make a property called 'delegateSet' to store the delegates. The method '-invokeDelegateItemsWithAction:withObjects:...' is used to wrap the delegate method and invoke when it needs to.
But the delegate method "-uploadTask:progressChange:" has a parameter which type is float, the app crash when it execute "va_arg(args, id)".
To solve this problem, I change the parameter from float to NSNumber, but the app still crashed when execute "[invocation invoke]" with error "EXC_BAD_ACCESS".
Why did this happen and how can I fix this problem?
Relative code In file: MyUploadClient.h
#protocol MyUploadClientDelegate <NSObject>
- (void)startUploadTask:(MyVideo *)video;
- (void)didUploadTask:(MyVideo *)video error:(NSError * __nullable)error;
- (void)uploadTask:(NSString *)videoId progressChange:(float)progress;
……
#end
#interface MyUploadClient : NSObject
+ (instancetype)sharedClient;
- (void)addDelegate:(id<MyUploadClientDelegate>)delegate;
- (void)removeDelegate:(id<MyUploadClientDelegate>)delegate;
……
#end
Relative code In file: MyUploadClient.m
#interface MyUploadClientDelegateItem : NSObject
#property (nonatomic, weak) id<MyUploadClientDelegate> delegate;
- (instancetype)initWithDelegate:(id<MyUploadClientDelegate>)delegate;
#end
#implementation MyUploadClientDelegateItem
- (instancetype)initWithDelegate:(id<MyUploadClientDelegate>)delegate {
self = [super init];
if (self) {
[self setDelegate:delegate];
}
return self;
}
#end
#interface MyUploadClient ()
#property (nonatomic, strong) NSMutableSet *delegateSet;
#end
#implementation MyUploadClient
- (NSMutableSet *)delegateSet {
if (!_delegateSet) {
_delegateSet = [NSMutableSet set];
}
return _delegateSet;
}
- (void)addDelegate:(id<MyUploadClientDelegate>)delegate {
for (MyUploadClientDelegateItem *item in self.delegateSet) {
if (delegate == item.delegate) {
return ;
}
}
MyUploadClientDelegateItem *delegateItem = [[MyUploadClientDelegateItem alloc] initWithDelegate:delegate];
[self.delegateSet addObject:delegateItem];
}
- (void)removeDelegate:(id<MyUploadClientDelegate>)delegate {
MyUploadClientDelegateItem *deleteItem = nil;
for (MyUploadClientDelegateItem *item in self.delegateSet) {
if (delegate == item.delegate) {
deleteItem = item;
}
}
if (deleteItem) {
[self.delegateSet removeObject:deleteItem];
}
}
- (void)startUploadWithVideo:(MyVideo *)video {
……
[self invokeDelegateItemsWithAction:#selector(startUploadTask:) withObjects:video, nil];
……
}
- (void)uploadProgressChanged:(float)progress videoId:(NSString *)videoId {
……
[self invokeDelegateItemsWithAction:#selector(uploadTask:progressChange:) withObjects:videoId, progress, nil];
……
}
- (void)invokeDelegateItemsWithAction:(SEL)action withObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION {
NSMutableArray *deleteItems = [NSMutableArray arrayWithCapacity:0];
NSSet *copySet = [NSSet setWithSet:self.delegateSet];
for (MyDelegateItem *item in copySet) {
if (item.delegate && [item.delegate respondsToSelector:action]) {
NSMethodSignature *sigOfAction = [(id)item.delegate methodSignatureForSelector:action];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sigOfAction];
[invocation setTarget:item.delegate];
[invocation setSelector:action];
if (firstObj) {
NSInteger argsIndex = 2;
va_list args;
va_start(args, firstObj);
id argObject = firstObj;
while (argObject) {
if ([argObject isKindOfClass:[NSValue class]]) {
void *value;
[argObject getValue:&value];
[invocation setArgument:&value atIndex:argsIndex];
} else {
[invocation setArgument:&argObject atIndex:argsIndex];
}
argObject = va_arg(args, id);
argsIndex++;
}
va_end(args);
}
[invocation invoke];
}
if (!item.delegate) {
[deleteItems addObject:item];
}
}
for (id obj in deleteItems) {
[self.delegateSet removeObject:obj];
}
}
#end

How to implement the method "+ (BOOL)resolveClassMethod:(SEL)sel"

I'm learning runtime, when I code this:
#implementation Son
- (instancetype)init
{
self = [super init];
if (self) {
[self performSelector:#selector(sel) withObject:nil];
}
return self;
}
id dynamicMethodIMP(id self, SEL _cmd)
{
NSLog(#"%s:dynamic method",__FUNCTION__);
return #"1";
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
class_addMethod(self.class, sel, (IMP)(dynamicMethodIMP), "##:");
[super resolveInstanceMethod:sel];
return YES;
}
#end
It's running very well.
But when I code this:
#implementation Son
id dynamicMethodIMP(id self, SEL _cmd)
{
NSLog(#"%s:dynamic method",__FUNCTION__);
return #"1";
}
+ (BOOL)resolveClassMethod:(SEL)sel {
class_addMethod(self.class, sel, (IMP)(dynamicMethodIMP), "##:");
[super resolveClassMethod:sel];
return YES;
}
#end
//Other file
[Son performSelector:#selector(sel) withObject:nil];
It crashed with:
+[Son sel]: unrecognized selector sent to class 0x10da8a588
What should I do to implement the method + (BOOL)resolveClassMethod:(SEL)sel?
Replace self.class with object_getClass
+ (BOOL)resolveClassMethod:(SEL)sel {
class_addMethod(object_getClass(self), sel, (IMP)(dynamicMethodIMP), "##:");
[super resolveClassMethod:sel];
return YES;
}
Reason:
object_getClass will return meta class if parameter is a class object。
If you read Chinese, you can read my blog to see more details about meta class.

Missing context for method declaration in IOS 8 for MWPhotoBrowser

I am having problems with MWPhoto library after moving to IOS 8 and XCODE 6. The error occurs in PSTCollectionView class. I am wondering why it returns me Missing context for method declaration error. Below you can find the code and image for error.
#import <objc/runtime.h>
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
NSMethodSignature *signature = [super methodSignatureForSelector:selector];
if (!signature) {
NSString *selString = NSStringFromSelector(selector);
if ([selString hasPrefix:#"_"]) {
SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]);
signature = [super methodSignatureForSelector:cleanedSelector];
}
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
NSString *selString = NSStringFromSelector([invocation selector]);
if ([selString hasPrefix:#"_"]) {
SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]);
if ([self respondsToSelector:cleanedSelector]) {
invocation.selector = cleanedSelector;
[invocation invokeWithTarget:self];
}
}else {
[super forwardInvocation:invocation];
}
}
#end
i update PSTCollectionView from github and now works fine
https://github.com/steipete/PSTCollectionView

Accessing Singleton object second times caused app to crash

I have a a singleton class here is the code
#import <Foundation/Foundation.h>
#import "CustomColor.h"
#interface Properties : NSObject {
UIColor *bgColor;
CustomColor *bggColor;
}
#property(retain) UIColor *bgColor;
#property (retain) CustomColor *bggColor;
+ (id)sharedProperties;
#end
#import "Properties.h"
static Properties *sharedMyProperties = nil;
#implementation Properties
#synthesize bgColor;
#synthesize bggColor;
#pragma mark Singleton Methods
+ (id)sharedProperties
{
#synchronized(self)
{
if(sharedMyProperties == nil)
[[self alloc] init];
}
return sharedMyProperties;
}
+ (id)allocWithZone:(NSZone *)zone
{
#synchronized(self)
{
if(sharedMyProperties == nil)
{
sharedMyProperties = [super allocWithZone:zone];
return sharedMyProperties;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
// never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init])
{
bgColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];
FSColor *bc = [[FSColor alloc] init];
bc.red = bc.green = bc.blue = bc.hue = bc.sat = bc.bri = 0;
bggColor = bc;
}
return self;
}
- (void)dealloc
{
// Should never be called, but just here for clarity really.
[bgColor release];
[bggColor release];
[super dealloc];
}
#end
I have a UIView' subclass. in which i am using it. I am calling drawRect method after each second. It only run once and then app crashes.
- (void)drawRect:(CGRect)rect
{
Properties *sharedProprties = [Properties sharedProperties];
…...
….
CGContextSetFillColorWithColor(context, [[sharedProprties bgColor] CGColor]);
…..
}
What if you do self.bgColor = [UIColor colorWithRed:...]?
Without the self. I think you may be accessing the ivar directly, and therefore assigning it an autoreleased object which won't live very long (rather than using the synthesized property setter, which would retain it). I could be wrong about this, I'm stuck targeting older Mac OS X systems so I haven't been able to play much with Objective-C 2.0.
Your static sharedProperties gets never assigned. It is missing in the init method or in the sharedProperties static method.
Here's a sample pattern for singletons (last post)
Also accessing properties without self. may cause bad access errors too.
Regards
Not an answer, but note that a simple call to [Properties alloc] will mean it's no longer a singleton!
+ (id)sharedProperties
{
#synchronized(self)
{
if(sharedMyProperties == nil)
{
sharedMyProperties = [[self alloc] init];
}
}
return sharedMyProperties;
}

What should my Objective-C singleton look like? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
My singleton accessor method is usually some variant of:
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
#synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
What could I be doing to improve this?
Another option is to use the +(void)initialize method. From the documentation:
The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.) The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses.
So you could do something akin to this:
static MySingleton *sharedSingleton;
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
sharedSingleton = [[MySingleton alloc] init];
}
}
#interface MySingleton : NSObject
{
}
+ (MySingleton *)sharedSingleton;
#end
#implementation MySingleton
+ (MySingleton *)sharedSingleton
{
static MySingleton *sharedSingleton;
#synchronized(self)
{
if (!sharedSingleton)
sharedSingleton = [[MySingleton alloc] init];
return sharedSingleton;
}
}
#end
[Source]
Per my other answer below, I think you should be doing:
+ (id)sharedFoo
{
static dispatch_once_t once;
static MyFoo *sharedFoo;
dispatch_once(&once, ^ { sharedFoo = [[self alloc] init]; });
return sharedFoo;
}
Since Kendall posted a threadsafe singleton that attempts to avoid locking costs, I thought I would toss one up as well:
#import <libkern/OSAtomic.h>
static void * volatile sharedInstance = nil;
+ (className *) sharedInstance {
while (!sharedInstance) {
className *temp = [[self alloc] init];
if(!OSAtomicCompareAndSwapPtrBarrier(0x0, temp, &sharedInstance)) {
[temp release];
}
}
return sharedInstance;
}
Okay, let me explain how this works:
Fast case: In normal execution sharedInstance has already been set, so the while loop is never executed and the function returns after simply testing for the variable's existence;
Slow case: If sharedInstance doesn't exist, then an instance is allocated and copied into it using a Compare And Swap ('CAS');
Contended case: If two threads both attempt to call sharedInstance at the same time AND sharedInstance doesn't exist at the same time then they will both initialize new instances of the singleton and attempt to CAS it into position. Whichever one wins the CAS returns immediately, whichever one loses releases the instance it just allocated and returns the (now set) sharedInstance. The single OSAtomicCompareAndSwapPtrBarrier acts as both a write barrier for the setting thread and a read barrier from the testing thread.
static MyClass *sharedInst = nil;
+ (id)sharedInstance
{
#synchronize( self ) {
if ( sharedInst == nil ) {
/* sharedInst set up in init */
[[self alloc] init];
}
}
return sharedInst;
}
- (id)init
{
if ( sharedInst != nil ) {
[NSException raise:NSInternalInconsistencyException
format:#"[%# %#] cannot be called; use +[%# %#] instead"],
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
NSStringFromSelector(#selector(sharedInstance)"];
} else if ( self = [super init] ) {
sharedInst = self;
/* Whatever class specific here */
}
return sharedInst;
}
/* These probably do nothing in
a GC app. Keeps singleton
as an actual singleton in a
non CG app
*/
- (NSUInteger)retainCount
{
return NSUIntegerMax;
}
- (oneway void)release
{
}
- (id)retain
{
return sharedInst;
}
- (id)autorelease
{
return sharedInst;
}
Edit: This implementation obsoleted with ARC. Please have a look at How do I implement an Objective-C singleton that is compatible with ARC? for correct implementation.
All the implementations of initialize I've read in other answers share a common error.
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
The Apple documentation recommend you check the class type in your initialize block. Because subclasses call the initialize by default. There exists a non-obvious case where subclasses may be created indirectly through KVO. For if you add the following line in another class:
[[MySingletonClass getInstance] addObserver:self forKeyPath:#"foo" options:0 context:nil]
Objective-C will implicitly create a subclass of MySingletonClass resulting in a second triggering of +initialize.
You may think that you should implicitly check for duplicate initialization in your init block as such:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
But you will shoot yourself in the foot; or worse give another developer the opportunity to shoot themselves in the foot.
- (id) init { <----- Correct!
NSAssert(_instance == nil, #"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL;DR, here's my implementation
#implementation MySingletonClass
static MySingletonClass * _instance;
+ (void) initialize {
if (self == [MySingletonClass class]){
_instance = [[MySingletonClass alloc] init];
}
}
- (id) init {
ZAssert (_instance == nil, #"Duplication initialization of singleton");
self = [super init];
if (self) {
// Initialization
}
return self;
}
+ (id) getInstance {
return _instance;
}
#end
(Replace ZAssert with our own assertion macro; or just NSAssert.)
A thorough explanation of the Singleton macro code is on the blog Cocoa With Love
http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html.
I have an interesting variation on sharedInstance that is thread safe, but does not lock after the initialization. I am not yet sure enough of it to modify the top answer as requested, but I present it for further discussion:
// Volatile to make sure we are not foiled by CPU caches
static volatile ALBackendRequestManager *sharedInstance;
// There's no need to call this directly, as method swizzling in sharedInstance
// means this will get called after the singleton is initialized.
+ (MySingleton *)simpleSharedInstance
{
return (MySingleton *)sharedInstance;
}
+ (MySingleton*)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
{
sharedInstance = [[MySingleton alloc] init];
// Replace expensive thread-safe method
// with the simpler one that just returns the allocated instance.
SEL origSel = #selector(sharedInstance);
SEL newSel = #selector(simpleSharedInstance);
Method origMethod = class_getClassMethod(self, origSel);
Method newMethod = class_getClassMethod(self, newSel);
method_exchangeImplementations(origMethod, newMethod);
}
}
return (MySingleton *)sharedInstance;
}
Short answer: Fabulous.
Long answer: Something like....
static SomeSingleton *instance = NULL;
#implementation SomeSingleton
+ (id) instance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == NULL){
instance = [[super allocWithZone:NULL] init];
}
});
return instance;
}
+ (id) allocWithZone:(NSZone *)paramZone {
return [[self instance] retain];
}
- (id) copyWithZone:(NSZone *)paramZone {
return self;
}
- (id) autorelease {
return self;
}
- (NSUInteger) retainCount {
return NSUIntegerMax;
}
- (id) retain {
return self;
}
#end
Be sure to read the dispatch/once.h header to understand what's going on. In this case the header comments are more applicable than the docs or man page.
I've rolled singleton into a class, so other classes can inherit singleton properties.
Singleton.h :
static id sharedInstance = nil;
#define DEFINE_SHARED_INSTANCE + (id) sharedInstance { return [self sharedInstance:&sharedInstance]; } \
+ (id) allocWithZone:(NSZone *)zone { return [self allocWithZone:zone forInstance:&sharedInstance]; }
#interface Singleton : NSObject {
}
+ (id) sharedInstance;
+ (id) sharedInstance:(id*)inst;
+ (id) allocWithZone:(NSZone *)zone forInstance:(id*)inst;
#end
Singleton.m :
#import "Singleton.h"
#implementation Singleton
+ (id) sharedInstance {
return [self sharedInstance:&sharedInstance];
}
+ (id) sharedInstance:(id*)inst {
#synchronized(self)
{
if (*inst == nil)
*inst = [[self alloc] init];
}
return *inst;
}
+ (id) allocWithZone:(NSZone *)zone forInstance:(id*)inst {
#synchronized(self) {
if (*inst == nil) {
*inst = [super allocWithZone:zone];
return *inst; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
#end
And here is an example of some class, that you want to become singleton.
#import "Singleton.h"
#interface SomeClass : Singleton {
}
#end
#implementation SomeClass
DEFINE_SHARED_INSTANCE;
#end
The only limitation about Singleton class, is that it is NSObject subclass. But most time I use singletons in my code they are in fact NSObject subclasses, so this class really ease my life and make code cleaner.
This works in a non-garbage collected environment also.
#interface MySingleton : NSObject {
}
+(MySingleton *)sharedManager;
#end
#implementation MySingleton
static MySingleton *sharedMySingleton = nil;
+(MySingleton*)sharedManager {
#synchronized(self) {
if (sharedMySingleton == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedMySingleton;
}
+(id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [super allocWithZone:zone];
return sharedMySingleton; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
-(void)dealloc {
[super dealloc];
}
-(id)copyWithZone:(NSZone *)zone {
return self;
}
-(id)retain {
return self;
}
-(unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be release
}
-(void)release {
//do nothing
}
-(id)autorelease {
return self;
}
-(id)init {
self = [super init];
sharedMySingleton = self;
//initialize here
return self;
}
#end
Shouln't this be threadsafe and avoid the expensive locking after the first call?
+ (MySingleton*)sharedInstance
{
if (sharedInstance == nil) {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
}
}
return (MySingleton *)sharedInstance;
}
Here's a macro that I put together:
http://github.com/cjhanson/Objective-C-Optimized-Singleton
It is based on the work here by Matt Gallagher
But changing the implementation to use method swizzling as described here by Dave MacLachlan of Google.
I welcome comments / contributions.
How about
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
if (gInstance == NULL) {
#synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
}
return(gInstance);
}
So you avoid the synchronization cost after initialization?
For an in-depth discussion of the singleton pattern in Objective-C, look here:
Using the Singleton Pattern in Objective-C
KLSingleton is:
Subclassible (to the n-th degree)
ARC compatible
Safe with alloc and init
Loaded lazily
Thread-safe
Lock-free (uses +initialize, not #synchronize)
Macro-free
Swizzle-free
Simple
KLSingleton
You don't want to synchronize on self... Since the self object doesn't exist yet! You end up locking on a temporary id value. You want to ensure that no one else can run class methods ( sharedInstance, alloc, allocWithZone:, etc ), so you need to synchronize on the class object instead:
#implementation MYSingleton
static MYSingleton * sharedInstance = nil;
+( id )sharedInstance {
#synchronized( [ MYSingleton class ] ) {
if( sharedInstance == nil )
sharedInstance = [ [ MYSingleton alloc ] init ];
}
return sharedInstance;
}
+( id )allocWithZone:( NSZone * )zone {
#synchronized( [ MYSingleton class ] ) {
if( sharedInstance == nil )
sharedInstance = [ super allocWithZone:zone ];
}
return sharedInstance;
}
-( id )init {
#synchronized( [ MYSingleton class ] ) {
self = [ super init ];
if( self != nil ) {
// Insert initialization code here
}
return self;
}
}
#end
Just wanted to leave this here so I don't lose it. The advantage to this one is that it's usable in InterfaceBuilder, which is a HUGE advantage. This is taken from another question that I asked:
static Server *instance;
+ (Server *)instance { return instance; }
+ (id)hiddenAlloc
{
return [super alloc];
}
+ (id)alloc
{
return [[self instance] retain];
}
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
instance = [[Server hiddenAlloc] init];
}
}
- (id) init
{
if (instance)
return self;
self = [super init];
if (self != nil) {
// whatever
}
return self;
}
static mySingleton *obj=nil;
#implementation mySingleton
-(id) init {
if(obj != nil){
[self release];
return obj;
} else if(self = [super init]) {
obj = self;
}
return obj;
}
+(mySingleton*) getSharedInstance {
#synchronized(self){
if(obj == nil) {
obj = [[mySingleton alloc] init];
}
}
return obj;
}
- (id)retain {
return self;
}
- (id)copy {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
if(obj != self){
[super release];
}
//do nothing
}
- (id)autorelease {
return self;
}
-(void) dealloc {
[super dealloc];
}
#end
I know there are a lot of comments on this "question", but I don't see many people suggesting using a macro to define the singleton. It's such a common pattern and a macro greatly simplifies the singleton.
Here are the macros I wrote based on several Objc implementations I've seen.
Singeton.h
/**
#abstract Helps define the interface of a singleton.
#param TYPE The type of this singleton.
#param NAME The name of the singleton accessor. Must match the name used in the implementation.
#discussion
Typcially the NAME is something like 'sharedThing' where 'Thing' is the prefix-removed type name of the class.
*/
#define SingletonInterface(TYPE, NAME) \
+ (TYPE *)NAME;
/**
#abstract Helps define the implementation of a singleton.
#param TYPE The type of this singleton.
#param NAME The name of the singleton accessor. Must match the name used in the interface.
#discussion
Typcially the NAME is something like 'sharedThing' where 'Thing' is the prefix-removed type name of the class.
*/
#define SingletonImplementation(TYPE, NAME) \
static TYPE *__ ## NAME; \
\
\
+ (void)initialize \
{ \
static BOOL initialized = NO; \
if(!initialized) \
{ \
initialized = YES; \
__ ## NAME = [[TYPE alloc] init]; \
} \
} \
\
\
+ (TYPE *)NAME \
{ \
return __ ## NAME; \
}
Example of use:
MyManager.h
#interface MyManager
SingletonInterface(MyManager, sharedManager);
// ...
#end
MyManager.m
#implementation MyManager
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
SingletonImplementation(MyManager, sharedManager);
// ...
#end
Why a interface macro when it's nearly empty? Code consistency between the header and code files; maintainability in case you want to add more automatic methods or change it around.
I'm using the initialize method to create the singleton as is used in the most popular answer here (at time of writing).
With Objective C class methods, we can just avoid using the singleton pattern the usual way, from:
[[Librarian sharedInstance] openLibrary]
to:
[Librarian openLibrary]
by wrapping the class inside another class that just has Class Methods, that way there is no chance of accidentally creating duplicate instances, as we're not creating any instance!
I wrote a more detailed blog here :)
To extend the example from #robbie-hanson ...
static MySingleton* sharedSingleton = nil;
+ (void)initialize {
static BOOL initialized = NO;
if (!initialized) {
initialized = YES;
sharedSingleton = [[self alloc] init];
}
}
- (id)init {
self = [super init];
if (self) {
// Member initialization here.
}
return self;
}
My way is simple like this:
static id instanceOfXXX = nil;
+ (id) sharedXXX
{
static volatile BOOL initialized = NO;
if (!initialized)
{
#synchronized([XXX class])
{
if (!initialized)
{
instanceOfXXX = [[XXX alloc] init];
initialized = YES;
}
}
}
return instanceOfXXX;
}
If the singleton is initialized already, the LOCK block will not be entered. The second check if(!initialized) is to make sure it is not initialized yet when the current thread acquires the LOCK.
I've not read through all the solutions, so forgive if this code is redundant.
This is the most thread safe implementation in my opinion.
+(SingletonObject *) sharedManager
{
static SingletonObject * sharedResourcesObj = nil;
#synchronized(self)
{
if (!sharedResourcesObj)
{
sharedResourcesObj = [[SingletonObject alloc] init];
}
}
return sharedResourcesObj;
}
I usually use code roughly similar to that in Ben Hoffstein's answer (which I also got out of Wikipedia). I use it for the reasons stated by Chris Hanson in his comment.
However, sometimes I have a need to place a singleton into a NIB, and in that case I use the following:
#implementation Singleton
static Singleton *singleton = nil;
- (id)init {
static BOOL initialized = NO;
if (!initialized) {
self = [super init];
singleton = self;
initialized = YES;
}
return self;
}
+ (id)allocWithZone:(NSZone*)zone {
#synchronized (self) {
if (!singleton)
singleton = [super allocWithZone:zone];
}
return singleton;
}
+ (Singleton*)sharedSingleton {
if (!singleton)
[[Singleton alloc] init];
return singleton;
}
#end
I leave the implementation of -retain (etc.) to the reader, although the above code is all you need in a garbage collected environment.
The accepted answer, although it compiles, is incorrect.
+ (MySingleton*)sharedInstance
{
#synchronized(self) <-------- self does not exist at class scope
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
Per Apple documentation:
... You can take a similar approach to synchronize the class methods of the associated class, using the Class object instead of self.
Even if using self works, it shouldn't and this looks like a copy and paste mistake to me.
The correct implementation for a class factory method would be:
+ (MySingleton*)getInstance
{
#synchronized([MySingleton class])
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}