I don´t fully understand how to use the Delegation pattern in obj-C. Basically I have a class: DigGameControlLayer.h and in it´s header I define a protocol with one required method that all users of this class needs to implement. Then I create the delegate property that I use within the code like any other property to delegate responsibility of what the moveObjectToPosition: method should do. So far so good I hope.
//DigGameControlLayer.h
#protocol DigGameControlLayerDelegate <NSObject>
-(void) moveObjectToNewPosition: (CCSprite *)object atSpeed:(float)moveSpeed;
#end
#property (assign) id <DigGameControlLayerDelegate> delegate;
Then the class that is using that class (in this case DigCharacter) says it adheres to the DigGameControlDelegate protocol
#interface DigGoblinPlayer : DigCharacter <DigGameControlLayerDelegate>
But what I don´t understand is where do i Initialize and set the delegate property a declared? Cause currently it does nothing when I use it in DigGameControlLayer since it´s null
[self.delegate moveObjectToNewPosition:object atSpeed:moveSpeed];
You can pass the delegate in the init method like so:
DigGoblinPlayer* player;
player = [[DigGoblinPlayer alloc] initWithName:(NSString*)name delegate:self];
Or set it separately:
DigGoblinPlayer* player;
player = [[DigGoblinPlayer alloc] initWithName:(NSString*)name];
player.delegate = self;
Which style you choose depends on if you always want/need a delegate, or if you want to be able to change/reset it later on.
In some cases you don't want the delegate to be a public property; then you'd use the first style.
You see a lot of example of this in the iOS SDK like here.
Note that self --which is just an example, and could an other object of course-- needs to implement this delegate. And name is something I made up.
in DigGoblinPlayer
implement the method
-(void) moveObjectToNewPosition: (CCSprite *)object atSpeed:(float)moveSpeed
{
}
this method will be called when the method calls in DigGameControlLayer
[self.delegate moveObjectToNewPosition:object atSpeed:moveSpeed];
Related
Is there any way to delegate to two objects at a time in Objective-C? I know that delegation pattern implies one response at a time and for multiple listeners and broadcasting there is notification center but notification does not return any value.
If I have a heavily network-based iOS project and need to delegate to multiple listeners and required to return values from them, in this scenario what approach should be the best?
In every class the delegate is one, so one delegate is informed about the event. But nothing forbids you to declare a class with a set of delegates.
Or use Observation instead. A class may be observed by multiple classes.
Example
As requested from the OP, since also some code would be useful, here is a way of doing it:
#interface YourClass()
#property (nonatomic, strong, readwrite) NSPointerArray* delegates;
// The user of the class shouldn't even know about this array
// It has to be initialized with the NSPointerFunctionsWeakMemory option so it doesn't retain objects
#end
#implementation YourClass
#synthesize delegates;
... // other methods, make sure to initialize the delegates set with alloc-initWithOptions:NSPointerFunctionsWeakMemory
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
[delegates addPointer: delegate];
}
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Remove the pointer from the array
for(int i=0; i<delegates.count; i++) {
if(delegate == [delegates pointerAtIndex: i]) {
[delegates removePointerAtIndex: i];
break;
}
} // You may want to modify this code to throw an exception if no object is found inside the delegates array
}
#end
This is a very simple version, you can do it in another way. I don't suggest to make public the delegates set, you never know how it could be used, and you can get an inconsistent state, specially with multithreading. Also, when you add/remove a delegate you may need to run additional code, so that's why making the delegates set private.
You may also a lot of other methods like delegatesCount for example.
PS: The code has been edited to be a NSPointerArray instead of a NSMutableSet, because as stated in the comments a delegate should be held with a weak pointer to avoid retain cycles.
In addition to Ramys answer you could use a [NSHashTable weakObjectsHashTable] instead of a
NSMutableSet. This would keep only a weak reference to your delegates and prevents you from running into memory leaks.
You will get the same behavior you already know from standard weak delegates #property (nonatomic, weak) id delegate;
#interface YourClass()
#property (nonatomic, strong) NSHashTable *delegates;
#end
#implementation YourClass
- (instancetype)init
{
self = [super init];
if (self) {
_delegates = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates addObject: delegate];
}
// calling this method is optional, because the hash table will automatically remove the delegate when it gets released
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates removeObject: delegate];
}
#end
Robbie Hanson wrote a multicast delegate implementation. Looks like what you need. He talks about it in more detail here, and how it is used in the XMPPFramework. He has some good discussion about one of the main problems which is how to handle the case where the multiple delegates implement a given method who's return value determines the class' behaviour (and the multiple delegates return different values). Relevant bits:
What is a MulticastDelegate?
The xmpp framework needs to support an unlimited number of extensions.
This includes the official extensions that ship with the framework, as
well as any number of extensions or custom code you may want to plug
into the framework. So the traditional delegate pattern simply won't
work. XMPP modules and extensions need to be separated into their own
separate classes, yet each of these classes needs to receive delegate
methods. And the standard NSNotification architecture won't work
either because some of these delegates require a return variable.
(Plus it's really annoying to extract parameters from a notification's
userInfo dictionary.)
So a MulticastDelegate allows you to plug into the framework using the
standard delegate paradigm, but it allows multiple classes to receive
the same delegate notifications. The beauty of this is that you don't
have to put all your xmpp handling code in a single class. You can
separate your handling into multiple classes, or however you see fit.
If you're writing the function that will call the delegates, you can have as many as you want. But if you're using a class (that you can't change) that calls the delegates, then you can't have more delegates than the class supports.
You could, if it worked out for you, have one delegate call another. Set up the first delegate so it will call the second delegate (whose pointer is stored in the first delegate object). This can be simple, with it pre-defined as to which calls are "passed on", or quite complex, using the dynamic call mechanisms of Objective-C.
One delegate can be setting for only one object but it's possible to store delegates in array.
Variant of Ramy Al Zuhouri is good but I want to say that it may be a problem to release delegates from array because NSArray (like NSMutableArray) classes retain all added objects but delegate in most cases is an assign property without retainCount. Retaining the delegate can bring to consequences that class with delegate implementation will have retainCount + 1.
Solution of this is store delegates in NSMutableArray like pointers to delegate methods.
I'm using singletone class with delegate header.
//YourClass.h file
#protocol YourDelegateProtocol <NSObject>
-(void)delegateMethod;
#end
#interface YourClass : NSObject
+(YourClass *)sharedYourClass;
- (void) addDelegate: (id<YourDelegateProtocol>) delegate;
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
#end
//YourClass.m file
#interface YourClass()
#property (nonatomic, retain) NSMutableArray *delegates;
-(void)runAllDelegates;
#end
#implementation YourClass
#synthesize delegates = _delegates;
static YourClass *sharedYourClass = nil;
+(YourClass *)sharedYourClass {
if (!sharedYourClass || sharedYourClass == nil) {
sharedYourClass = [YourClass new];
sharedYourClass.delegates = [NSMutableArray array];
}
return sharedYourClass;
}
-(void)addDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates addObject: pointerToDelegate];
}
-(void)removeDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates removeObject: pointerToDelegate];
}
-(void)runAllDelegates{
//this method will run all delegates in array
for(NSValue *val in sharedYourClass.delegates){
id<YourDelegateProtocol> delegate = [val pointerValue];
[delegate delegateMethod];
}
}
-(void)dealloc{
sharedYourClass.delegates =nil;
[sharedYourClass release], sharedYourClass =nil;
[super dealloc];
}
#end
//YourClassWithDelegateImplementation.h file
#include "YourClass.h"
#interface YourClassWithDelegateImplementation : NSObject <YourDelegateProtocol>
#end
//YourClassWithDelegateImplementation.m file
#implementation YourClassWithDelegateImplementation
-(id)init{
self = [super init];
if(self){
//...your initialization code
[[YourClass sharedYourClass] addDelegate:self];
}
return self;
}
-(void)delegateMethod{
//implementation of delegate
}
-(void)dealloc{
[[YourClass sharedYourClass] removeDelegate:self];
[super dealloc];
}
#end
If you want to call callbacks for classes B and C from a class A with only one delegate, you could create a delegate wrapper DWrap which has references to the classes B and C. Then class A calls the callbacks on B and C through DWrap.
I thought I had finally managed to understand the concept of a delegate until the following occurred: I changed my header file to remove the reference to the delegate and the Alert still worked. The only difference is that I lose code hinting.
//.h
#import <UIKit/UIKit.h>
//#interface ViewController : UIViewController <UIAlertViewDelegate>
#interface ViewController : UIViewController
- (IBAction)showMessage:(id)sender;
#end
//.m
#import "ViewController.h"
#implementation ViewController
- (IBAction)showMessage:(id)sender {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Hello World!"
message:#"Message."
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Button 1", #"Button 2", nil];
[message show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Button 1"])
{
NSLog(#"Button 1 was selected.");
}
}
#end
The <UIAlertViewDelegate> in your header is just an indication to the compiler that you intend to implement the delegate methods in your class. You will get warnings if you don't implement delegate methods that are marked as #required, but since most of the delegate methods are usually #optional your code will compile and run fine. That doesn't mean that you shouldn't add the delegates in your header though.
While you have already accepted an answer, there is more to this issue than is addressed there.
UIAlertViewDelegate is a protocol which implements the delegate design pattern. You may or may not need to officially inform the runtime that you conform to any given protocol (especially if it doesn't have any required methods) by adopting it, but this depends on the design of the class which declares the protocol. You adopt the protocol in your class by putting the protocol name in <>'s when declaring the class, like this:
#interface MyClass : NSObject <delegateProtocolName>
Since many protocol methods that are delegated are optional methods, they often test to see if the adopting class implements a particular method like this:
if ([self.delegate respondsToSelector:#selector(delegatedMethod:)]) {
// Do something
}
In this case, you do not need to conform to the protocol in your header file because it is testing to see if the specific delegate method has been implemented.
However, the test may be written like this instead (especially if you need to refer to multiple required methods/properties in the same function):
if ([self.delegate conformsToProtocol:#protocol(delegateProtocolName)]) {
// Do something
}
In this case, you must conform to the protocol in your header file or it will not pass the test.
To quote the documentation for conformsToProtocol (taken from The Objective-C Programming Language and emphasis added by me):
This method determines conformance solely on the basis of the formal
declarations in header files, as illustrated above. It doesn’t check
to see whether the methods declared in the protocol are actually
implemented—that’s the programmer’s responsibility.
The answer is apple doesn't want to require a class to implement the UIAlertViewDelegate protocol. If Apple wished to require that, it would make UIAlertView's delegate property of type id<UIAlertViewDelegate>. If you look at the documentation, it's not.
UIAlertView Class Reference
#property(nonatomic, assign) id delegate
They must have their reasons for not making it #property(nonatomic, assign) id<UIAlertViewDelegate> delegate.
The <UIAlertViewDelegate> which you have mentioned in your class means that you are implementing the AlertView delegate's methods in this class i.e. ViewController and delegate:self means that delegate methods of this object are define in current class.
If you want to define AlertView delegate's method in any other class, then you have to mention <UIAlertViewDelegate> in that class and implement methods in that particular class.
and also you have to change delegate:(classname).
I have a pretty simple setup for this unit test. I have a class that has a delegate property:
#interface MyClass : NSObject
...
#property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate;
...
#end
and I set the delegate in my test:
- (void)testMyMethod_WithDelegate {
id delegate = mockDelegateHelper(); // uses OCMock to create a mock object
[[delegate expect] someMethod];
myClassIvar.connectionDelegate = delegate;
[myClass someOtherMethod];
STAssertNoThrow([delegate verify], #"should have called someMethod on delegate.");
}
But the delegate is not actually set on line 3 of my unit test, so #someMethod is never called. When I change it to
myClassIvar.connectionDelegate = delegate;
STAssertNotNil(myClassIvar.connectionDelegate, #"delegate should not be nil");
it fails there. I'm using ARC, so my hunch was that the weak property was being deallocated. Sure enough, changing it to strong makes the STAssertNotNil pass. But I don't want to do that with a delegate, and I don't understand why that makes a difference here. From what I've read, all local references in ARC are strong, and STAssertNotNil(delegate) passes. Why is my weak delegate property nil when the same object in a local variable is not?
This is a bug in the iOS runtime. The following discussion has more detail. In a nutshell, the iOS ARC runtime can't seem to handle weak references to proxies. The OSX runtime can.
http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&t=252
As far as I understand from the discussion a bug report has been filed with Apple. If anyone has a sensible idea for a workaround...
I don't really know what's happening here, but OCMock returns an autoreleased NSProxy-descendant from the mockForProtocol: method, which I think is right. Maybe ARC has problems with NSProxies? Anyway, I've overcome this problem by declaring the variable __weak:
- (void)testMyMethod_WithDelegate {
// maybe you'll also need this modifier inside the helper
__weak id delegate = mockDelegateHelper();
...
It really doesn't need to be __strong (the default) in this case, as it's autoreleased and you're not keeping it around...
A workaround is to use Partial Mocks.
#interface TestMyDelegateProtocolDelegate : NSObject <MyDelegateProtocol>
#end
#implementation TestMyDelegateProtocolDelegate
- (void)someMethod {}
#end
#implementation SomeTest {
- (void)testMyMethod_WithDelegate {
id<MyDelegateProtocol> delegate = [[TestMyDelegateProtocolDelegate] alloc] init];
id delegateMock = [OCMockObject partialMockForObject:delegate]
[[[delegateMock expect] someMethod]
myClassIvar.connectionDelegate = delegate;
[myClass someOtherMethod];
STAssertNoThrow([delegate verify], #"should have called someMethod on delegate.");
}
#end
I am no ARC expert but my guess is that mockDelegateHelper() is returning a weak object. As a result delegate is nil before the second line of code executes. I would venture to guess that either the mockDelegateHelper() is the culprit or that OCMock is getting in the way with how it manipulates and creates objects.
I want to fire some code when a property is accessed and changed. I use #property and #synthesize in my code for my ivars. The properties are retained, so I'd like to keep that memory management stuff automatically generated by #synthesize.
However, I assume that #synthesize tells the compiler to generate the accessor methods code right where #synthesize is, so most of the cases at the top of the code, right?
And when I have a property foo, I get -setFoo and -foo methods. Could I then just make a method like this, to execute some more custom code when a property is changed?
-(void)setFoo {
// custom stuff
}
Now that's a problem. How to execute the first one? I wouldn't love to have a different name here. Is there maybe a way to let the #synthesize directive create other names for getter and setter methods, which I then call easily? And I would still be able to use the dot syntax then to access them?
You can use #property and #synthesize just like you normally would, but provide a custom setter or getter (or both) and those will be used instead. Typically I will do something like this:
// Override the setter
- (void)setName:(NSString *)aName
{
if (name == aName)
return;
[name release];
name = [aName retain];
//custom code here
}
When I use the set property, it will invoke my custom method. However, the get will still be synthesized.
If you provide an implemnetation for the setters or getters it will use that instead of the generated implementation. Its not hard to implement the "retaining" aspect of the getters and setters that are generated for you by the compiler when u synthesize, so you can just write your own getters and setters i would say and go with that.
One wacky solution is to create an abstract super class that does gives you the normal property synthesis.
Then create a concrete subclass that you will actually use, and that simply implements and override method (same signature) and calls super to do the actual setting.
This allows you to do whatever you want to do before or after the call to super's implementation.
Example:
#interface ALTOClassA : NSObject
#property NSString *catName;
#end
Nothing else needed in the .m beyond the stubbed file for this test.
Create the subclass, nothing needed specially in the #interface
#import "ALTOClassA.h"
#interface ALTOClassAJunior : ALTOClassA
#end
In the #implementation we do our override.
#import "ALTOClassAJunior.h"
#implementation ALTOClassAJunior
- (void)setCatName:(NSString*)aCatName {
NSLog(#"%#",NSStringFromSelector(_cmd));
[super setCatName:aCatName];
NSLog(#"after super: self.catName %#", self.catName);
}
#end
In use:
ALTOClassAJunior *aCAJ = [ALTOClassAJunior new];
NSLog(#"aCAS.catName %#", aCAJ.catName);
NSLog(#"set it to George.");
[aCAJ setCatName:#"George"];
NSLog(#"aCAS.catName %#", aCAJ.catName);
This allows you to leverage the autogenerated code, and still do stuff you want to do with your class. Abstract Super Class is often a useful solution for many things.
Yes, in your #property declaration, you can specify the getter and setter methods.
#property (readwrite,getter=privateGetFoo,setter=privateSetFoo:) NSObject * foo;
In your foo and setFoo: methods, call [self privateGetFoo] or [self privateSetFoo:f] then your custom code.
The object can also set an observer on itself with addObserver:forKeyPath:options:context:.
That said, I don't think either of these are very clean ways to do things. Better to write your own getter/setter as others have suggested.
I recently began trying my hand at using protocols in my Objective-C development as an (obvious) means of delegating tasks more appropriately among my classes. I completely understand the basic notion of protocols and how they work. However, I came across a roadblock when trying to create a custom protocol that in turn implements another protocol. I since discovered the solution, but I am curious why the following DOES NOT work:
#protocol STPickerViewDelegate < UIPickerViewDelegate >
- ( void )customCallback;
#end
#interface STPickerView : UIPickerView
{
id < STPickerViewDelegate > delegate;
}
#property ( nonatomic, assign ) id < STPickerViewDelegate > delegate;
#end
Then in a view controller, which conforms to STPickerViewDelegate:
STPickerView * pickerView = [ [ STPickerView alloc ] init ];
pickerView.delegate = self;
- ( void )customCallback
{
...
}
- ( NSString * )pickerView:( UIPickerView * )pickerView titleForRow:( NSInteger )row forComponent:( NSInteger )component
{
...
}
The problem was that pickerView:titleForRow:forComponent: was never being called. On the other hand, customCallback was being called just fine, which isn't too surprising. I don't understand why STPickerViewDelegate, which itself conforms to UIPickerViewDelegate, does not notify my view controller when events from UIPickerViewDelegate are supposed to occur. Per my understanding of Apple's documentation, if a protocol (A) itself conforms to another protocol (B), then a class (C) that conforms to the first protocol (A) must also conform to the second protocol (B), which is exactly the behavior I want and expected.
What I ended up doing was removing the id< STPickerViewDelegate > delegate property from STViewPicker and instead doing something like the following in my STViewPicker implementation where I want to evoke customCallback:
if ( [ self.delegate respondsToSelector:#selector( customCallback ) ] )
{
[ self.delegate performSelector:#selector( customCallback ) ];
}
This works just fine, but I really am puzzled as to why my original approach did not work.
The problem was that UIPickerView already has a delegate member variable, and you were declaring another one in a subclass which was what was being set, while the superclass's delegate variable remained nil and therefore any delegate methods would not be called on the class you expect it to be called on. In this case what you did is pretty much the only way to do it; if you need to extend the given protocol do so, have a class implement that, then just set the class as the UIPickerView's delegate.
Edit: btw, awesome avatar :)
I tried to do something similar - I assume you want to group extra methods you add to the UIImagePickerControllerDelegate in one file? I was running a UIImagePicker from two places and wanted it to behave the same way without duplicating code.
What I did was to add a category to the UIViewController, like this (below.) I'm fairly new to Objective-C (have used C++ for many years) so assuredly this probably violates the spirit of how you are "supposed" to do things (extending the protocol makes more sense), but my approach accomplished what I wanted, so I thought I'd toss it out.
UIViewController+imagePickerDelegate.h:
#interface UIViewController (ImagePickerDelegate) <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
-(void)configurePicker:(UIImagePickerController*)picker;
...
#end
UIViewController+imagePickerDelegate.m:
#import "UIViewController+imagePickerDelegate.h"
#implementation UIViewController (ImagePickerDelegate)
-(void)configurePicker:(UIImagePickerController*)picker
{
picker.delegate = self;
picker.allowsEditing = YES;
}
....
#end