How to pass values to a #protocol - objective-c

I'm trying to implement a protocol.
I've looked at the documentation here and I understand the concepts although I think I'm missing a few things.
I'm trying to make a view that the user taps on a filename in a table view triggering 'didSelectRowAtIndexPath' which will in turn notify the delegate that the user has selected a file (triggering didSelectFileName in the delegate) and passing the fileName. I've declared the protocol as follows;
#protocol FileList <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
My questions are:
How do i set the 'fileName' value so that when 'didSelectFileName' is called it has the current value in it
How do I tell my code to trigger 'didSelectFileName' in the delegate.

You cannot just send a message to a protocol (nor setting values). You send the message to a class that conforms to the protocol.
When you say a class conforms to a protocol (#interface MyClass : NSObject <MyProtocol> { etc) you can safely send any messages to the class with the selectors that conform to the methods in the protocol.
So if we take your protocol for example we can have a class that can send messages to a delegate:
#interface MyClass : NSObject {
id<FileList> _delegate;
}
#end
#implementation MyClass
- someMethod {
NSString *fn = #"Hello.";
[_delegate didSelectFileName:fn];
}
#end
Just make sure you implement the methods that are in your protocol in you delegate.
You don't need to redefine the methods in the interface of your delegate class.
Here are some good reads about protocols:
http://www.otierney.net/objective-c.html#protocols
http://mauvilasoftware.com/iphone_software_development/2008/05/a-brief-intro-to-objective-c-p.html
Protocol versus Category

//In table View method
- (void)tableView didSelectRowAtIndexPath....... {
UITableViewCell *cell = [tableView methodToGetCell];
if(delegate && [delegate respondsToSelector:#selector(didSelectFileName:)]){
[delegate didSelectFileName:cell.text];
}

Related

Custom delegate method not called 100

I am trying to use custom delegate between NSObject class and UIViewController class. delegate is declared in NSObject method as
#protocol MYDelegate <NSObject>
-(void)methodOne;
#end
#property(nonatomic,strong) id <MYDelegate> delegate;
and trying to call it by
if([delegate respondsToSelector:#selector(methodOne)]){
[delegate methodOne];
}
method is defined in ViewController class as
UIViewController <MYDelegate>
-(void)methodOne{
[self performSegueWithIdentifier:#"someScreenSegue" sender:self];
}
Not getting what I am missing here. delegate method is not getting called ever. I am getting self->delegate:
<nil>
Delegate is returning nil always
Delegates is call back mechanism. When you want to use a delegate you have to do the following:
Create the delegate protocol (which you did)
Have the class that implements the call back, implement the protocol (which you did)
Connect the delegate from the calling class to self to allow the call-back to happen (this is missing).
So you need somewhere in your code to assign the delegate property.

Call method with instance creator as receiver

I have class A, (NSDocument subclass) which stores my document data. Class A creates an instance of Class B, (NSView subclass) which manages the view. I want it so that every time the drawRect: method of Class B is called, it calls updateChangeCount: on Class A so that the user will know to save the document.
I'm not completely familiar with OSX projects and what exactly drawRect: does for NSView, so you may want to look into Richard J Ross III's comment. But on the general question of one object calling a method on the object that instantiated it:
ClassB.h
#protocol ClassBDelegate <NSObject>
#reqiured
- (void)someRequiredMethod;
#optional
- (void)someOptionalMethod;
#end
#interface ClassB <NSView>
#property (nonatomic, assign) id<ClassBDelegate> delegate;
// Other stuff you need in your interface
#end
ClassB.m
- (void)someClassBMethodThatNeedsToTriggerSomeClassAMethod {
// stuff
[self.delegate someRequiredMethod];
if ([self.delegate respondsToSelector:#selector(someOptionalMethod)]) {
[self.delegate someOptionalMethod];
}
// stuff
}
Now, in ClassA, be sure you conform to this protocol:
#import ClassB.h
#interface ClassA <ClassBDelegate>
And implement the required method:
- (void)someRequiredMethod {
// stuff
NSLog(#"Hello world!");
// stuff
}
And when you instantiate your ClassB object, be sure to set its delegate to yourself:
classB.delegate = self;
EDIT: Note, I put in an example of how ClassB can use optional methods as well as required methods.

Implementing a category on all classes conforming to a protocol

I have written a category on SCNRenderer that adds some camera utility methods. Those same methods would be equally useful to SCNView and SCNLayer. All three of the classes to which this category would be relevant conform to SCNSceneRenderer. Is it possible to write a category that applies not to a specific class, but to all classes that conform to a particular protocol?
The simplest way of doing this would be to write some utility functions that take an SCNSceneRenderer object:
void ABCDoSomethingUseful(id<SCNSceneRenderer> renderer)
{
//...
}
void ABCDoSomethingElseUseful(id<SCNSceneRenderer> renderer)
{
//...
}
If you want to use the method call syntax, or want to be able to override the implementation in subclasses, another option would be to implement the methods as a category on NSObject:
// This goes in a source file:
#interface NSObject (SCNSceneRendererConformance) <SCNSceneRenderer>
// Surpress compiler warnings about NSObject not responding to
// SCNSceneRenderer's messages
#end
#implementation NSObject (MyCategory)
- (void)abc_doSomethingUseful
{
//...
}
- (void)abc_doSomethingElseUseful
{
//...
}
#end
then expose them in a protocol:
// This goes in a header file:
#protocol MyProtocol <NSObject>
- (void)abc_doSomethingElseUseful;
- (void)abc_doSomethingUseful;
#end
and add an interface-only category for each class that conforms to SCNSceneRenderer declaring that it also conforms to your protocol:
// This also goes in a header file:
#interface SCNLayer (MyProtocolConformance) <MyProtocol>
#end
#interface SCNView (MyProtocolConformance) <MyProtocol>
#end
I don't think you can add category over a protocol, since protocol just defines interface not implementation. Whereas in category we need to implement as well.

Why do I not need to declare UIAlertViewDelegate in the header?

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).

How to create a delegator in objective C?

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