short call for singleton - objective-c

Update with working code. Problem was like #HotLinks state, that I did init instead of initWithBaseURL:url
I am using a Singleton in my App, based on this guide.
Now every time I use the singleton I do like this:
SingletonClass* sharedSingleton = [SingletonClass sharedInstance];
[sharedSingleton callAMethod];
// or
[[SingletonClass sharedInstance] callAMethod];
Is there a way to use a short syntax, especially if I have to use the Singleton several times? Something like:
[sc callAMethod];
I tried already this kind, but it did not work, as the init method was not called...
WebApi.h
#import "AFHTTPRequestOperationManager.h"
#import "SingletonClass.h"
#interface WebApi : AFHTTPRequestOperationManager
#property (nonatomic, strong) SingletonClass *sc;
+(WebApi*)sharedInstance;
-(void)sandbox;
#end
WebApi.m (updated with working code)
#import "WebApi.h"
#implementation WebApi
//-(WebApi*)init {
-(WebApi*)initWithBaseURL:url {
self = [super init];
if (self != nil) {
self.sc = [SingletonClass sharedInstance]; // is never called.
}
return self;
}
#pragma mark - Singleton methods
/**
* Singleton methods
*/
+(WebApi*)sharedInstance
{
static WebApi *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kApiHost]];
});
return sharedInstance;
}
-(void)sandbox {
DLog(#"test short singleton call: %#", [sc callAMethod];
}
#end
Debug Message
[WebApi sandbox] [Line 42] test short singleton call: (null)

I don't see how you can do this in any language. In Java, you would generally see
<Class>.getInstance().<blah>.
There's nothing stopping you from getting that instance inside a method where it will be used a lot, e.g.
WebApi *api = [WebApi sharedInstance];
then a whole lot of:
[api <method1>];
...
Does that get you there?
(Amusingly, a developer and I were discussing this issue yesterday because the example code Apple has for use of the accelerometer puts the motion manager in the app delegate and the syntax to get a hold of the manager is completely insane:
CMMotionManager *mManager = [(APLAppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
As you can see, they are making a local var and then diddling that from there on in the controller class.

You could declare a global variable and set it in your +sharedInstance method, then make sure you call +sharedInstance once.
But, really, don't bother. Using [SomeClass sharedInstance] makes it easy to quantify all uses of shared instances in your code base, as well as all uses of SomeClass's class level API. Both are quite useful for anyone else that ends up maintaining your code.
Secondly, it doesn't really save that much typing. Not enough to justify requiring everyone to learn about a new global.
(What Rob said):
Finally, if you are calling instance methods on the shared instance repeatedly in a scope, just use a local variable:
ThingManager *thingManager = [ThingManager sharedInstance];
[thingManager foo];
[thingManager bar];
[thingManager baz];

You can do it this way:
In .h file
#interface WebApi : AFHTTPRequestOperationManager
#property (nonatomic, strong) SingletonClass *sc;
...
+(id) methodName;
...
#end
In .m file
+(id) methodName
{
return [[WebApi shareInstance] instanceMethod];
}
- (id) instanceMethod
{
return #"SMTH";
}

Related

Delegating the even callback in objective-C

I am trying to wrap my head around how does the an event callback delegation works. So far I have written following code which btw works just fine:
Bridge.h
#protocol BridgeDelegate <NSObject>
- (void) bridgeLock;
#end
#interface Bridge : NSObject
+(instancetype) sharedInstance;
#property (weak, nonatomic) id<BridgeDelegate> bridgeDelegate;
- (void) wipe;
#end
Bridge.m
#implementation Bridge
+(instancetype) sharedInstance {
static dispatch_once_t pred;
static id shared = nil;
dispatch_once(&pred, ^{
shared = [[super alloc] initUniqueInstance];
});
return shared;
}
-(instancetype) initUniqueInstance {
return [super init];
}
- (void) wipe
{
NSLog(#"lock in bridge called");
if(self.bridgeDelegate)
{
[self.bridgeDelegate bridgeLock];
}
}
#end
Plugin.h
#interface Plugin : NSObject<BridgeDelegate>
#property (strong, nonatomic) Bridge *bridge;
- (void) pluginInitialize;
#end
Plugin.m
#implementation Plugin
- (void) pluginInitialize
{
self.bridge = [Bridge sharedInstance];
self.bridge.bridgeDelegate = self;
}
- (void)bridgeLock
{
NSLog(#"lock in plugin called");
}
#end
When I call the following code in applicationDidBecomeActive
Bridge* bridge = [Bridge sharedInstance];
Plugin* plugin = [[Plugin alloc] init];
[plugin pluginInitialize];
[bridge wipe];
I get the following expected output:
lock in bridge called
lock in plugin called
Now my questions:
How exactly is the delegate work? In the sense, Plugin is only implementing the function bridgewipe(), right? Why and how bridgeLock is being called at first place?
Does this have anything to the fact that Bridge is a singleton. Had I made Bridge a non singleton class, will the end result be same.
1.How exactly is the delegate work? In the sense, Plugin is only implementing the function bridgewipe(), right? Why and how bridgeLock is being called at first place?
In the above pasted code "Plugin.m" is implementing - (void)bridgeLock
Does this have anything to the fact that Bridge is a singleton. Had I made Bridge a non singleton class, will the end result be same.
No
Bridge* bridge = [Bridge sharedInstance];
this bridge we call it B1;
B1 is a instance make by the method "sharedInstance";
then you call the following code :
Plugin* plugin = [[Plugin alloc] init];
[plugin pluginInitialize];
pluginInitialize method your code is
{
self.bridge = [Bridge sharedInstance];
self.bridge.bridgeDelegate = self;
}
when code executed, self.bridge is also a instance make by the method "sharedInstance"; it's equal to B1 with address and also make B1's delegate == self;
so when you call [bridge wipe];
It will nslog #"lock in bridge called";
Because self.bridgeDelegate is not nil, so delegate will call the bridgeLock method;
Then nslog #"lock in plugin called".
About your second question, when you make Bridge a non singleton class, I think the result will be different.
#hariszaman, explanation is right but I would like to expand more on this so it can help someone in the future. Basically this is what happening.
I am creating an instance of the Bridge class. This instance in the memory has a reference variable of type BridgeDelegate.
As I instancetiate Plugin, BridgeDelegate variable starts pointing to the the Plugin class instance.
Now when lock is called, it calls the bridgelock method of the class that is pointed by BridgeDelegate pointer which in this case is Plugin.
It doesn't matter if the Bridge class is not singleton because following line in pluginInitialize:
{
self.bridge = [Bridge sharedInstance];
self.bridge.bridgeDelegate = self;
}
will be changed to :
{
self.bridge = [[Bridge alloc] init];
self.bridge.bridgeDelegate = self;
}
and steps 1,2 and 3 will be repeated the same way.

Objective-C setting/accessing iVars in singleton class' superclass

I've got two classes: A superclass, User and its subclass, UserSession. User is extremely simple, just a container for some instanceVariables:
//User.h
#interface User : NSObject
- (id)initWithJSON:(NSDictionary *)JSONDictionary;
-(NSNumber *)getUserID;
-(NSString *)getUserName;
-(NSString *)getUserUsername;
-(NSString *)getUserEmail;
-(NSString *)getUserBio;
-(void)setUserID:(NSNumber *)userID;
-(void)setUserName:(NSString *)userName;
-(void)setUserUsername:(NSString *)userUsername;
-(void)setUserEmail:(NSString *)userEmail;
-(void)setUserBio:(NSString *)userBio;
#end
and
//User.m
#interface User()
#end
#implementation User
NSNumber *_userID;
NSString *_userName;
NSString *_userUsername;
NSString *_userEmail;
NSString *_userBio;
- (id)initWithJSON:(NSDictionary *)JSONDictionary
{
self = [super init];
if (!self)
return nil;
_userID = JSONDictionary[#"userID"];
_userName = JSONDictionary[#"userName"];
_userUsername = JSONDictionary[#"userUsername"];
_userEmail = JSONDictionary[#"userEmail"];
_userBio = JSONDictionary[#"userBio"];
return self;
}
plus associated setters and getters for the iVars.
UserSession is a singleton class that subclasses User:
//UserSession.m
#interface UserSession ()
#end
#implementation UserSession
static UserSession *_session = nil;
-(void)updateUserForUserSessionWithParams:(NSDictionary *)params
{
[self setUserID:params[#"userId"]];
[self setUserName:params[#"userName"]];
[self setUserUsername:params[#"userUsername"]];
[self setUserEmail:params[#"userEmail"]];
[self setUserBio:params[#"userBio"]];
}
+ (instancetype)sharedSession
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Create a session
_session = [[UserSession alloc] init];
});
return _session;
}
Heres the problem: when I make calls like
[[UserSession sharedSession]
updateUserForUserSessionWithParams:#{#"userId":#1],
#"userName":#"Steve Smith",
#"userUsername":responseObject[#"ssmith"],
#"userEmail":responseObject[#"ssmith#test.com"],
#"userBio":responseObject[#"I'm steve smith"]}];
and then elsewhere:
NSString* stringName = [[UserSession sharedSession] getUserName];
NSString* stringUsername = [[UserSession sharedSession] getUserUsername];
NSString* stringBio = [[UserSession sharedSession] getUserBio];
these getters return nil!
Sorry for all the code, but I think I'm doing something dumb wrong. Any help would be amazing.
Thanks in advance!
I don't have a -[UserSession init] though. What would I put in there?
Well, for starters a subclass should always call it's superclass's initializer, so you should call -initWithJSON: or some other User initializer. That won't entirely solve your problem in this case, but Objective-C relies heavily on conventions to make things work and it's best to stick to those conventions unless you really understand what you're doing.
I think the main problem with your code is here:
#implementation User
NSNumber *_userID;
NSString *_userName;
NSString *_userUsername;
NSString *_userEmail;
NSString *_userBio;
Those aren't instance variables you're declaring -- they're file-scoped global variables. You can declare instance variables as part of your #implementation block, but you still need the braces like you do for an #interface block:
#implementation User
{
NSNumber *_userID;
NSString *_userName;
NSString *_userUsername;
NSString *_userEmail;
NSString *_userBio;
}
//...
I'd recommend using properties for these anyway. It's easy to get accessor methods wrong, and finding those kinds of problems (as in this case) usually isn't easy if you're just starting out. It might not be easy even if you have a lot of experience, but that's hard to know; people with a lot of experience usually use properties.

AFNetworking AFHTTPClient Subclassing, Singleton Client and Delegates

I'm writing a REST API layer with AFNetworking for an iOS project. I have some questions about what I have written so far, so I'm turning to stackoverflow for some guidance/answers.
Here are the guidelines of what I'm trying to achieve:
A base class (DRAPI : AFHTTPClient) that will initialize a singleton client, just as the cocoadocs for AFHTTPClient recommend.
A "base" delegate for DRAPI: DRAPIDelegate, that holds methods for displaying errors in an unified format.
Subclasses of DRAPI that deal with certain routes of my REST API. For example, CRUD operations on Users are responsability of DRUserAPI, which is a child class of DRAPI.
Each subclass of DRAPI has its own delegate. For DRUserAPI, there's DRUserAPIDelegate, which extends DRAPIDelegate.
Here is a quick example of how things are written so far:
DRAPI.h
#interface DRAPI : AFHTTPClient
- (void) apiGetCallWithRoute:(NSString*)route
parameters:(NSDictionary*)parameters
onSuccess:(void(^)(id))successBlock
onError:(void(^)(NSArray* errors))errorBlock;
#end
#protocol DRAPIDelegate <NSObject>
-(void) DRAPIErrorFromServer:(NSArray*)errors;
#end
DRAPI.m
#implementation DRAPI
+(DRAPI*) sharedClient
{
static DRAPI *aSharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&once_token, ^{
_sharedClient = [DRAPI alloc] initWithBaseURL:[NSURL URLWithString:#"http://127.0.0.1:3000/api"];
});
return aSharedClient;
}
-(id) initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if (self) {
// configuration goes here... skipping because it is not important.
}
return self;
}
#pragma mark - Helper methods for Server Calls
- (void) apiGetCallWithRoute:(NSString*)route
parameters:(NSDictionary*)parameters
onSuccess:(void(^)(id))successBlock
onError:(void(^)(NSArray* errors))errorBlock
{
[[DRAPI sharedClient] getPath:route
parameters:addAuthenticationParametersTo(parameters)
success:^(AFHTTPRequestOperation *operation, id responseObject) {
successBlock(responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
errorBlock( processError() );
}];
}
#end
DRUserAPI.h
#interface DRUserAPI: DRAPI
#property (weak, nonatomic) id<DRUserAPIDelegate>delegate;
+(DRUserAPI*) APIWithDelegate:(id<DRUserAPIDelegate>)delegate;
-(void) createUser:(NSString*)username password:(NSString*)password;
// ... more methods would be declared here...
#end
#protocol DRUserAPIDelegate <NSObject, DRAPIDelegate>
-(void) DRUserAPIOnUserCreated:(MyUserModel*)newUser;
// more delegate methods would be here...
#end
DRUserAPI.m
#implementation DRUserAPI
#synthesize delegate;
+(DRUserAPI*) APIWithDelegate:(id<DRUserAPIDelegate>)delegate
{
DRUserAPI * client = [DRUserAPI new];
client.delegate = delegate;
return client;
}
-(void) createUser:(NSString*)username password:(NSString*)password
{
[self apiGetCallWithRoute:#"users/create"
parameters:#{#"username" : username, #"password": password}
onSuccess:^(id response) {
NSDictionary *parsedJSON = response;
[delegate DRUserAPIOnUserCreated:[MyUserModel newModelFromDictionary:parsedJSON];
}
onError:^(NSArray *errors) {
[delegate DRAPIErrorFromServer:errors];
}];
}
#end
A fellow co-worker brought to my attention that delegates and singletons do not mix. I still want to manage delegates, though. I'm thinking that good solution would be pass the singleton instance of the delegate to the method I'm calling inside the API subclass.
Is this a good idea?
Thanks!
I prefer an implementation based on composition instead of subclassing, even if the AFNetworking docs recommend to subclass AFHTTPClient.
I would inject the AFHTTPClient in the DRAPI and this one in the DRUserAPI, making both of them simple subclasses of NSObject. A flat design is cleaner IMO and it makes it easier to unit test your classes.
Instead of having singletons you can create an injector class responsible of creating your whole object graph, calling it only in your application delegate.
For this you should use a block based API instead of delegates since you would only have one instance of DRAPI and you don't want to set its delegate before any call to it (you could have another class like DRUserAPI where you inject the DRAPI instance).
It's not perfect, but it works. Why so many delegates? It seems that you moving to a infinite loop of singletons. I think you should stop...

Singleton gets deallocated

I've created a simple singleton class to hold static data for my projects.
The first time I access this singleton is onEnter method in my Cocos2d scene. However when I try to access it again later in another method (same scene) this singleton is already released. I'm confused, how do I keep my singleton from being deallocated?
Here's my singleton's interface part:
#import <Foundation/Foundation.h>
#interface OrchestraData : NSObject
+(OrchestraData *)sharedOrchestraData;
#property (retain, readonly) NSArray *animalNames;
#end
Implementation:
#import "OrchestraData.h"
#implementation OrchestraData
#synthesize animalNames = animalNames_;
+(OrchestraData*)sharedOrchestraData
{
static dispatch_once_t pred;
static OrchestraData *_sharedOrchestraData = nil;
dispatch_once(&pred, ^{ _sharedOrchestraData = [[OrchestraData alloc] init]; });
return _sharedOrchestraData;
}
-(id)init {
if (self = [super init]) {
animalNames_ = [NSArray arrayWithObjects:#"giraffe", #"giraffe", #"giraffe", #"giraffe", nil];
}
return self;
}
#end
I'm using my singleton this way:
[[OrchestraData sharedOrchestraData] animalNames];
Update:
I took a fresh look into it with NSZombies enabled, it appears as if my NSArrays were released, not the singleton itself. What do I do?
You must implement your singleton in this way:
1) in .h file of your Singleton Class:
+ (SingletonClass *)instance;
2) in .m file:
+ (SingletonClass *)instance {
static SingletonClass* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
//your init code here
});
return instance;
}
If you want to call your singleton, just call [SingletonClass instance].
If your are interesting what is "dispatch_once_t", read about Grand Central Dispatch:
http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
RE Update:
Your NSArray deallocates because you're using the autorelease initializer arrayWithObjects and you assign it directly to the ivar animalNames_. Therefore it is not retained.
To fix this, assign the array to the property:
self.animalNames = [NSArray arrayWithObjects:#"giraffe", #"giraffe", #"giraffe", #"giraffe", nil];
Btw, under ARC this wouldn't have been an issue since the ivar would have been a strong (retaining) reference. I don't get tired encouraging anyone to switch to ARC. It's been available for well over a year now and there's absolutely no point in using MRC code anymore! It really pains me to see how developers still don't use the easier, faster, and straightforward option. (rant off) :)
You setup a pointer wherever you need it.
-(void)someMethod {
MySingleton *singleton = [MySingleton sharedSingleton];
singleton.data = YES; //dumb example to show you did something...
}
-(void)someOtherMethod {
MySingleton *singleton = [MySingleton sharedSingleton]; //You have to create a new pointer...
singleton.data = NO; //another dumber example to show you did something...
}
Note: this assumes that you have created a singleton the same way I have... your code might be different therefore causing my answer not to apply...
You need to overwrite the below method inside your singleton class, because in your program, if someone has initialised [[SingletonClass alloc] init] then singleton will have another instance and release it will cause an error.
+ (id)allocWithZone:(NSZone *)zone{
return [[self SingletonClass] retain];
}
- (id)copyWithZone:(NSZone *)zone{
return self;
}
- (id)retain{
return self;
}

Objective C - Category to modify a singleton object?

I know that the whole point of singleton is to instantiate 1 instance of the onject and reuse it, but when it comes to unit testing I want to be able to renew the singleton object before every test.
I tried to use a category to access the singleton object and release it but It's not accessible by categories any idea what's the best way to achieve this?
#implementation SingletonClass
static SingletonClass *singleton;
+ (SingletonClass*)sharedInstance
{
if (!singleton)
{
singleton = [[SingletonClass alloc] init];
}
return singleton;
}
#end
.
#implementation SingletonClass(Unit Testing Additions)
+ (void)killInstance
{
// I get an error here and I cannot access the singleton Object
[singleton release], singleton = nil;
}
#end
By the very definition of singleton, you can't do this.
If it is your class, don't make it a singleton.
If it isn't your class, doing this will fail.
I'm not sure whether this will work, but maybe you could just override the sharedInstance class method and manage the singleton yourself:
#implementation SingletonClass (Unit Testing Additions)
static SingletonClass *myVeryOwnSharedInstance;
+ (SingletonClass *) sharedInstance
{
if (!myVeryOwnSharedInstance)
myVeryOwnSharedInstance = [[self alloc] init];
return myVeryOwnSharedInstance;
}
+ (void) killInstance
{
[myVeryOwnSharedInstance release];
// if release is overridden to do no-op, maybe just invoke -dealloc directly
myVeryOwnSharedInstance = nil;
}
#end
If you want access to your singleton global variable outside of the file in which it's declared, you'll need to make it globally accessible using extern.
At the top of SingletonClass.h, put this:
extern SingletonClass *singletonClassSingleton;
In your SingletonClass.m, use this:
SingletonClass *singletonClassSingleton = nil;
Then assuming you have #import "SingletonClass.h" in your unit test .m file, you should be able to add:
#implementation SingletonClass(Unit Testing Additions)
+ (void)killInstance
{
[singletonClassSingleton release], singletonClassSingleton = nil;
}
#end
The reason I've renamed singleton to singletonClassSingleton is that the variable is now global - if you have a bunch of singleton classes, you need these variables to have unique names, like dataManagerSingleton, resourceManagerSingleton or whatever.
Here is my own solution.
#implementation SingletonClass(Unit Testing Additions)
//Override
static SingletonClass *singleton;
+ (void)killInstance
{
// I get an error here and I cannot access the singleton Object
[singleton release], singleton = nil;
}
//Override
+ (SingletonClass*)sharedInstance
{
if (!singleton)
{
singleton = [[SingletonClass alloc] init];
}
return singleton;
}
#end