Delegating the even callback in objective-C - 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.

Related

short call for singleton

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";
}

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

Singleton's property memory management

I'm trying to write my little app and experiencing some memory management problems.
At first, I have Game singleton object with property:
//Game.h
#interface Game : NSObject
#property (nonatomic, retain) MapBuildingsLayer *mapBuildingsLayer;
+(Game *) game;
-(BOOL) addObject:(NSString *) objName At:(CGPoint) pt;
#end
where MapBuildingsLayer is just cocos2d CCLayer instance
//Game.m
#implementation Game
#synthesize mapBuildingsLayer = _mapBuildingsLayer;
static Game *instance = nil;
+ (Game *)game {
#synchronized(self) {
if (instance == nil) {
instance = [[Game alloc] init];
}
}
return instance;
}
-(BOOL) addObject:(NSString *)objName At:(CGPoint)pt
{
if([objName isEqualToString:OBJ_TYPE_PIT])
{
if([[Game game].mapBuildingsLayer addPitAt:pt]) //app crashes here
{
[self toggleConstructionMode];
return YES;
}
}
return NO;
}
#end
In MapBuildingsLayer.m's init method I use Game's mapBuildingsLayer property to store a reference to this CCLayer instance in my singleton (for future use in other methods):
//MapBuildingsLayer.m
#implementation MapBuildingsLayer
-(id) init
{
if( (self=[super init])) {
[Game game].mapBuildingsLayer = self;
}
return self;
}
When I call Game's addObject:objName At: method, my app crashes with EXC_BAD_ACCESS.
How I must declare property in Game singleton to use it from other places in my app's lifetime?
You typically don't use the singleton in the class itself, try changing
if([[Game game].mapBuildingsLayer addPitAt:pt]) //app crashes here
to
if([self.mapBuildingsLayer addPitAt:pt]) //app crashes here
You should be using [Game game] external to the class to get into the singleton instance of your class and call its methods, but internal to the class you would just refer to it as self like normal.
Typically if you're going to use a game singleton this isn't how you'd use it. Try thinking of it like this with a giant state machine, Create a CCScene subclass which will initialize all of your respective CCLayer subclasses and control them. Then from the statemachine you can load the appropriate initializing its scene and that will create everything under it.
In your applicationDidFinishLaunching method you simply have your singleton object load your first scene. I'd really recommend checking out the Learning Cocos2d Book as it covers this singleton state engine very well and I think would clear up all your questions.
Bottom line is have the state engine load the scene which loads the layers.
No where in your code i am seeing your mapBuildingsLayer initialized. I hope before returning your instance you should also do
instance.mapBuildingsLayer = [CCLayer alloc] init];
I think the way you are assigning the mapBuildingsLayer is wrong. Remove [Game game].mapBuildingsLayer = self from your MapBuildingsLayer init method and instead add the following inside Game init method:
self.mapBuildingsLayer = [[MapBuildingsLayer alloc] init] autorelease];
now it is initialized inside your singleton init method so you can access it simply as [Game game].mapBuildingsLayer anywhere outside the Game class. If this doesnt work try posting what addPitAt: does.
hope this helps

creating instances in objective c

Here is my code:
//ECHOAppDelegate.m
#implementation ECHOAppDelegate
...
#end
//PtyView.m
#interface PtyView (PtyPrivate)
-(void)startTask;
-(void) didRead: (NSNotification *)fileNoty;
#end
#implementation PtyView
...
-(void)startTask {
//starts task
}
#end
Now, how do I trigger "startTask" from ECHOAppDelegate.m? I need to create an instance? I'm a total beginner :D
Any example code would be awesome!
Thanks,
Elijah
-(void)startTask; appears to be private implementation and in theory should not be called from external classes.
To answer your question, you can call it something like this:
PtyView *v = [[PtyView alloc] init];
[v startTask];
[v release];
Though you will get a warning saying, PtyView might not respond to startTask. Since it is not in public interface of class.
Update: Above code assumes that when startTask returns, you are done with this object. But something tells me that you might be using async callbacks. If that is the case then startTask might return immediately and you won't release it then and there. Normally in this case, you will be notified by PtyView about the completion of task. So you release it when the task is complete.
Update2:
Making a method public is easy. You just declare it in the public interface (the header file of class):
//in PtyView.h
#interface PtyView
-(void)startTask;
#end
//in PtyView.m
#implementation PtyView
...
-(void)startTask {
//starts task
}
#end
Notice that there is no category defined in the interface declaration.
self represent the current object.
You just need to call the method like that.
[self startTask];
How about subclassing ECHOAppDelegate? (Then make sure PtyView inherits from NSObject?)
// cf. http://amath.colorado.edu/pub/mac/programs/PseudoTTY.zip
#interface ECHOAppDelegate : PtyView
...
#end
#implementation ECHOAppDelegate
- (id) init
{
self = [super init];
if (!self) return nil;
...
return self;
}
...
[self startTask];
...
#end