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).
Related
Another way of phrasing this question: is it possible for a subclass to be a delegate of its super class? I'm trying to make my code reusable within my app and have a situation where the subsclass needs to implement two methods for it to be functional. How can I ensure this occurs? Or what is the proper way of defining these methods?
Update
I didn't mean to imply that I want the compiler to generate flags. I just want a clean way of organizing my code. Currently I override methods of the superclass. Using that approach the superclass can call [super methodToOverride] and it works. However this doesn't feel very clean to me as there's no way to specify "these are the methods you should override" aside from putting a comment somewhere.
In obj-c, it is not possible to force subclasses to overwrite methods of its superclass. But you can raise an exception in the superclass, should it ever be called because the subclass did not implement a certain method.
But a subclass can be a delegate of its superclass, if the superclass does not implement certain methods, and you can enforce that the delegate implements these methods, if the superclass specifies the protocol, i.e. required methods, and the subclass adopts it.
If you want to force your subclass to implement methods from super class, you can do this as below:
//In super class
- (id)someMethod:(SomeObject*)bla
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
Your app will crash if subclass will not implement this method and you don't need to call
[super someMethod:bla];
There is no way to do this in compile time. However you can raise an exception in the base class.
Something like this:
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:#"You must override %# in a subclass", NSStringFromSelector(_cmd)]
userInfo:nil];
If your question is "how can I get the compiler to flag that a certain class doesn't implement a certain function" then I would say
Define a protocol with non-optional methods -- "By default, all methods declared in a protocol are required methods. This means that any class that conforms to the protocol must implement those methods."
Define a class ("stub") that declares it implements the protocol
Now when a subclass of your stub class is written, the compiler will flag it as an error if the mandatory method(s) aren't implemented
I know that it's awful, but supposed that you need to do this since your 3rdParty SDK requires this design pattern, you could use a Factory pattern:
Supposed then to have the base class MyParentAPIClient and two sub classes like MyFacebookAPIClient and MyGooglePlusAPIClient and that you do something like
self.myAPIClient = [MyParentAPIClient alloc] initWithAPIKey:apiKey];
and that you have defined
##interface MyParentAPIClient : NSObject {
}
-(void)callAPI;
#end
and you have override this in the two subclasses
#implementation MyFacebookAPIClient
-(void)callAPI {
[super callAPI];
// do something specific for this api client
}
#end
and
#implementation MyGooglePlusAPIClient
-(void)callAPI {
[super callAPI];
// do something specific for this api client
}
#end
Then you are doing in your controller
[self.myAPIClient callAPI];
but the super class MyParentAPIClient method is being called.
Now you could do a factory in the base class like:
-(void)callAPI {
if([self isKindOfClass:[MyFacebookAPIClient class]]) {
[((MyFacebookAPIClient*)self) callAPI];
} else if([self isKindOfClass:[MyGooglePlusAPIClient class]]) {
[((MyGooglePlusAPIClient*)self) callAPI];
}
}
Of course this have a downside that is to do not call the super in the sub classes that now become:
#implementation MyFacebookAPIClient
-(void)callAPI {
// [super callAPI]; the factory method called that
// do something specific for this api client
}
#end
and
#implementation MyGooglePlusAPIClient
-(void)callAPI {
// [super callAPI]; being called in the factory
// do something specific for this api client
}
#end
The good news is that there is no change in the methods calls since as soon as you call from the controller:
[self.myAPIClient callAPI];
You will have the calls
[MyParentAPIClient callAPI]; // parent class
[MyFacebookAPIClient callAPI]; // sub class
The other downside is that the parent class must known the subclass instances.
Now if we take a look at the factory:
if([self isKindOfClass:[MyFacebookAPIClient class]]) {
[((MyFacebookAPIClient*)self) callAPI];
} else if([self isKindOfClass:[MyGooglePlusAPIClient class]]) {
[((MyGooglePlusAPIClient*)self) callAPI];
}
}
we could make it better like in several way. Take a look at Dynamic type cast from id to class in objective c and Is there an equivalent to C++'s dynamic cast in Objective-C? or Objective-C dynamic_cast?
Good luck!
The UIGestureRecognizerSubclass.h pattern from UIKit is worth a look, that has all the protected methods that should be overridden and that header is not in the framework include, it is only included in subclasss' .m files. Also, nowadays you can tag methods with NS_REQUIRES_SUPER to require overrides to call super, however it can only be used in interfaces, not protocols so that might influence your design.
For super advanced code, NSAccessibilityProtocols.h in AppKit uses a protocol tag to require subclasses to re-implement methods, even if already implemented by a superclass. Here is an example of that you can paste right into in header in your currently open Xcode project:
NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION
#protocol Protocol
#property (readonly) id theWorstOfTimes;
// -(void)testMethod; // uncomment to test problem
#end
// In this example, ClassA adopts the protocol.
#interface ClassA : NSObject <Protocol>
#property (readonly) id theWorstOfTimes;
#end
#implementation ClassA
- (id)theWorstOfTimes{
return nil; // default implementation does nothing
}
-(void)testMethod{}
#end
// This class subclasses ClassA (which also adopts 'Protocol').
#interface ClassB : ClassA <Protocol>
#end
#implementation ClassB // expected-warning {{property 'theWorstOfTimes' requires method 'theWorstOfTimes' to be defined - use #synthesize, #dynamic or provide a method implementation in this class implementation}}
#end
In Xcode you'll see a yellow line at ClassB's expected-warning that the property method is missing. NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION is just a macro for __attribute__((objc_protocol_requires_explicit_implementation)) and this code sample is modified from the test harness of that feature here.
Although this looks great there is a slight problem. Currently this only works for methods that implement protocols, it used to work also for methods but a bug has been introduced in 2014 via a misunderstanding on the purpose of this feature and thus now it is limited to property methods. I have emailed the author to make them aware so hopefully it changed back to its original and proper behavior. To test the bug you can uncomment the method in the protocol and you will see there is no warning in ClassB. Hopefully you can change some of your methods to read-only properties to at least get some use out of it. On the plus side when Xcode offers to "Fix" the issue it does add stubs for the missing methods.
Here is some documentation on NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION:
ImplementingAccessibilityforCustomControls
nsaccessibilitybutton
If you used this then pat yourself on the back for becoming an ObjC expert if you weren't already!
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];
In the apps I worked on, I often found such lines of code
[delegate aFunction];
that generated the "instance method "aFunction" not found (return type defaults to id)" warning
Now, I did a bit of research on SO and found out that the warning can be removed by declaring the function for cases when you call it on self ([self aFunction];), but none of the answers said anything about my case, when I use a delegate.
So, long story short, what can I do to correctly call a delegate's method inside another class?
Things appear to work fine, so this is not a major issue, but a warning means I'm not doing something completely correct so I would like to learn what's the best practice for such cases
Thank you for your help in advance!
So, if I'm understanding you correctly, your issues can be taken away by declaring your protocol as follows:
#class SomeClass;
#protocol SomeClassDelegate <NSObject>
#required
- (void)thisObjectDidSomething:(SomeClass*)instance;
#optional
- (void)thisObjectDidSomethingUnimportant:(SomeClass*)instance;
#end
Then your delegate ivar and property look like this (use assign instead of weak if you're not using ARC):
#interface SomeClass () {
__weak id<SomeClassDelegate> delegate_;
}
#property (weak) id<SomeClassDelegate> delegate;
And in the .h file of any class that's going to implement that protocol, do this:
#interface TCReader : NSObject <SomeClassDelegate> {
}
Since it's safe to call selectors on nil, for required methods, you can just:
[self.delegate thisObjectDidSomething:self]
But for optional methods, you'd better:
if ([self.delegate respondsToSelector:#selector(thisObjectDidSomethingUnimportant:)]) {
[self.delegate thisObjectDidSomethingUnimportant:self]
}
The main point here is that by declaring and making use of a protocol, you let XCode know that those methods are defined for objects implementing the protocol. If you require that your delegate implement that protocol, then Xcode knows that your delegate has those methods defined.
I am trying to learn, how to implement delegation pattern in objective C. But the discussion almost exclusively concentrates on the adoption of protocols and then implementing the delegate methods that come with particular protocol - or - the delegation principle alone - or protocols alone.
What I am unable to find, is a easy to understand material about how to write a class that will serve as a delegator. By that I mean the class, which the message of some event will come from and which will provide the protocol for receiving that message - kind of 2in1 description. (protocols and delegation).
For the purpose of my learning, I'd like to go along the following trivial example, using an iPhone, a Cocoa touch application and Xcode4.2, using ARC, no Storyboard or NIBs.
Let's have a class with name "Delegator", which is a subclass of NSObject. The Delegator class has NSString instance variable named "report" and adopts the UIAccelerometerDelegate protocol.In the Delegator implementation, I will implement the the delegate method
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
This delegate method will create a NSString #"myReport" and store it in the report variable anytime there is an accelerometer event. Further, I want to have a second class named ReportsStorage (a subclass of NSobject), which can store some Nsstring (report) in its instance variable called latestReport.
So far so good.
Now lets get back to theDelegator Class. I'd like to implement a protocol in Delegator named ReportsDelegate which will notify the class that adopts it (the ReportsStorage class), that a report was generated and will pass this report through the delegate method, which should be (I believe) something like this
-(void)delegator:(Delegator *)delegator didCreateNewReport:(NSString *)report;
Can you please provide the code for Delegator Class (incl. the "delegate" property), that will achieve this, with a description what each line of code means?
Thanks in advance, EarlGrey
You'll need to declare the delegate property as an id<ReportsDelegate> type. That is, any object type (id) conforming to the ReportsDelegate protocol (<ReportsDelegate>). Then, if the delegate method is considered optional, check if the delegate responds to that selector before calling it. (respondsToSelector:).
Like so:
Delegator.h
#import <Foundation/Foundation.h>
// Provide a forward declaration of the "Delegator" class, so that we can use
// the class name in the protocol declaration.
#class Delegator;
// Declare a new protocol named ReportsDelegate, with a single optional method.
// This protocol conforms to the <NSObject> protocol
#protocol ReportsDelegate <NSObject>
#optional
-(void)delegator:(Delegator *)delegator didCreateNewReport:(NSString *)report;
#end
// Declare the actual Delegator class, which has a single property called 'delegate'
// The 'delegate' property is of any object type, so long as it conforms to the
// 'ReportsDelegate' protocol
#interface Delegator : NSObject
#property (weak) id<ReportsDelegate> delegate;
#end
Delegator.m
#import "Delegator.h"
#implementation Delegator
#synthesize delegate;
// Override -init, etc. as needed here.
- (void)generateNewReportWithData:(NSDictionary *)someData {
// Obviously, your report generation is likely more complex than this.
// But for purposes of an example, this works.
NSString *theNewReport = [someData description];
// Since our delegate method is declared as optional, check whether the delegate
// implements it before blindly calling the method.
if ([self.delegate respondsToSelector:#selector(delegator:didCreateNewReport:)]) {
[self.delegate delegator:self didCreateNewReport:theNewReport];
}
}
#end
- (void)someMethod
{
if ( [delegate respondsToSelector:#selector(operationShouldProceed)] )
{
if ( [delegate operationShouldProceed] )
{
// do something appropriate
}
}
}
The documentation says:
The precaution is necessary only for optional methods in a formal protocol or methods of an informal protocol
What does it mean? If I use a formal protocol I can just use [delegate myMethod]?
You use it pretty much just when you think you need to: to check to see if an object implements the method you are about to call. Usually this is done when you have an optional methods or an informal protocol.
I've only ever used respondsToSelector when I'm writing code that must communicate with a delegate object.
if ([self.delegate respondsToSelector:#selector(engineDidStartRunning:)]) {
[self.delegate engineDidStartRunning:self];
}
You sometimes would want to use respondsToSelector on any method that returns and id or generic NSObject where you aren't sure what the class of the returned object is.
Just to add to what #kubi said, another time I use it is when a method was added to a pre-existing class in a newer version of the frameworks, but I still need to be backwards-compatible. For example:
if ([myObject respondsToSelector:#selector(doAwesomeNewThing)]) {
[myObject doAwesomeNewThing];
} else {
[self doOldWorkaroundHackWithObject:myObject];
}
As kubi mentioned respondsToSelector is normally used when you have a an instance of a method that conforms to a protocol.
// Extend from the NSObject protocol so it is safe to call `respondsToSelector`
#protocol MyProtocol <NSObject>
// #required by default
- (void) requiredMethod;
#optional
- (void)optionalMethod;
#end
Given and instance of this protocol we can safely call any required method.
id <MyProtocol> myObject = ...
[myObject requiredMethod];
However, optional methods may or may not be implemented, so you need to check at runtime.
if ([myObject respondsToSelector:#selector(optionalMethod)])
{
[myObject optionalMethod];
}
Doing this will prevent a crash with an unrecognised selector.
Also, the reason why you should declare protocols as an extension of NSObjects, i.e.
#protocol MyProtocol <NSObject>
Is because the NSObject protocol declares the respondsToSelector: selector. Otherwise XCode would think that it is unsafe to call it.
Old question, but I have learned to be very cautios with using stuff like addTarget:#selector(fu:) because the method name is not checked nor included in refactoring by XCODE. This has caused me quite some trouble already. So now I made it a habbit to always embed stuff like addTarget or addObserver in a respondsToSelector-Check like so:
if([self respondsToSelector:#selector(buttonClicked:)]){
[self.button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}else{
DebugLog(#"Warning - a class or delegate did not respond to selector in class %#", self);
}
I know its not super elegant, but i'd rather add some boilerplate code than have an unexpected crash of my apps in the App Store.