protocol method is not being called by the delegate object - iphone

Another case of protocol method not being called - NO idea what am I doing wrong here...
Here is the code, omitting unnecessary info...
first header file: AccessNumber.h
#protocol AddItemDelegate <NSObject>
#required
- (void) processSuccessful: (BOOL)success;
#end
#interface AccessNumber : UIViewController <UITableViewDelegate, UITableViewDataSource, ABPeoplePickerNavigationControllerDelegate, UIAlertViewDelegate> {
id <AddItemDelegate> delegate;
}
#property (retain) id <AddItemDelegate> delegate;
#end
first .m file: AccessNumber.m - I am calling the protocol method from viewdidload just for testing purposes, it should basically get called from another method, but same thing for the sake of this convo (tried both of course)
#import "AccessNumber.h"
#import "History.h"
#synthesize delegate;
- (void)viewDidLoad
{
[super viewDidLoad];
....
[[self delegate] processSuccessful:YES];
}
second file header: History.h
#interface History : UIViewController <UITableViewDelegate, UITableViewDataSource, AddItemDelegate> {
....
}
method implementation in history.m
- (void) processSuccessful: (BOOL)success {
NSLog(#"SUCCESS");
}
Appreciate any help. Thanks!

In the code i don't see something like:
theAccessNumber.delegate = self;
You must set the History instance as the delegate property of the AccessNumber instance.
Regards.

The code seems a little bit funny but you are not telling your "AccessNumber" class who is his delegate, even though you are making the "History" class implement the protocol established by yourself (otherwise you would get a warning).
You have to set the delegate for the "AccessNumber" class like this when setting it up from within "AccessNumber.m":
self.delegate = historyInstance;
or like this when setting it up from within "History.m":
accessNumberInstance.delegate = self;

There are very vew situations where you should retain a delegate, normally your delagate will outlive the object. So change your property from retain to assign. And be sure you are setting the delegate. Where are you doing it? If your object really depends on it you should be passing it in the constructor (iniWithDelagate). Try doing a NSLog before calling the delagate method just to see if it isn't nil.

Related

Trying to Implement Delegate Inheritance

I have a class called ToolbarView which is a subclass of UIView and basically creates a UIView that has a disappearing / reappearing UIToolbar on top. I also have a subclass of ToolbarView called DraggableToolbarView enables the user to drag the view around the screen.
I need to create a delegate for ToolbarView so it can notify another object / class of when the toolbar reappears and disappears. I also need to create a delegate for DraggableToolbarView so I can notify another object / class when the view is dragged. DraggableToolbarViews delegate will also need to notify another object / class of when the toolbar reappears and disappears.
So I decided to implement ToolbarViewDelegate, and have DraggableToolbarViewDelegate inherit from it and have its own method like following:
ToolbarView.h
#import <UIKit/UIKit.h>
#protocol ToolbarViewDelegate;
#interface ToolbarView : UIView <UIGestureRecognizerDelegate>
{
id <ToolbarViewDelegate> _toolbarViewDelegate;
}
#property(nonatomic, assign) id <ToolbarViewDelegate> toolbarViewDelegate;
#end
ToolbarView.m
#import "ToolbarView.h"
#import "ToolbarViewDelegate.h"
...
- (void) showBars
{
...
if (self.toolbarViewDelegate)
{
[self.toolbarViewDelegate toolbarViewWillShowToolbar:self];
}
...
}
- (void) hideBars
{
...
if (self.toolbarViewDelegate)
{
[self.toolbarViewDelegate toolbarViewWillHideToolbar:self];
}
...
}
ToolbarViewDelegate.h
#class ToolbarView;
#protocol ToolbarViewDelegate
#required
- (void) toolBarViewWillShowToolbar:(ToolbarView *)toolbarView;
- (void) toolBarViewWillHideToolbar:(ToolbarView *)toolbarView;
#end
DraggableToolbarView.h
#import "ToolbarView.h"
#protocol DraggableToolbarViewDelegate;
#interface DraggableToolbarView : ToolbarView
{
id <DraggableToolbarViewDelegate> _draggableToolbarViewDelegate;
}
#property(nonatomic, assign) id <DraggableToolbarViewDelegate> draggableToolbarViewDelegate;
#end
DraggableToolbarView.m
#import "DraggableToolbarView.h"
#import "DraggableToolbarViewDelegate.h"
...
- (void)drag:(UIPanGestureRecognizer *)sender
{
...
if (self.draggableToolbarViewDelegate)
{
[self.draggableToolbarViewDelegate draggableToolbarViewWillDrag:self];
}
...
}
...
DraggableToolbarViewDelegate.h
#import "ToolbarViewDelegate.h"
#class DraggableToolbarView;
#protocol DraggableToolbarViewDelegate <ToolbarViewDelegate>
#required
- (void) draggableToolbarViewWillDrag:(DraggableToolbarView *)draggableToolbarView;
#end
SomeViewController.h
#import <UIKit/UIKit.h>
#import "ToolbarViewDelegate.h"
#import "DraggableToolbarViewDelegate.h"
#interface SomeViewController : UIViewController <ToolbarViewDelegate, DraggableToolbarViewDelegate>
{
}
#end
SomeViewController.m
#import "DraggableToolbarView.h"
...
- (void) toolbarViewWillShowToolbar:(ToolbarView*)toolbarView
{
//NSLog(#"Toolbar Showed");
}
- (void) toolbarViewWillHideToolbar:(ToolbarView*)toolbarView
{
//NSLog(#"Toolbar Hidden");
}
- (void) draggableToolbarViewWillDrag:(DraggableToolbarView*)draggableToolbarView
{
//NSLog(#"Dragged");
}
...
[draggableToolbarView setDraggableToolbarViewDelegate:self];
...
When I do this only the DraggableToolbarDelegate methods are responding. However when I also do [drabbleToolbarView setToolbarViewDelegate:self] it works. I've tried doing each delegate separately without inheritence and it works fine so I believe the problem isn't in any other part of the code.
Anyone might know why? I figured by making the protocols inherit, I wouldn't also have to set the ToolbarViewDelegate for a DraggableToolbar object.
UPDATE: Added a lot more code
In your code, any given DraggableToolbarView instance has two properties to connect to delegates, one called toolbarViewDelegate which it inherits from its superclass, and one called draggableToolbarViewDelegate which is defined in DraggableToolbarView itself. You've got to set both of those if you want the controller to get all the delegate messages.
What you're trying to do is possible, however. You need to use the same property name in both your view classes, so that there is only one delegate connection for any instance.
First, change the name of the delegate in the superclass. (Note that you don't need, and indeed shouldn't bother, to declare an ivar for the property -- it's created by #synthesize.)
#interface ToolbarView : UIView <UIGestureRecognizerDelegate>
#property (nonatomic, assign) id <ToolbarViewDelegate> delegate;
#end
You will use the same property name in the subclass.
#interface DraggableToolbarView : ToolbarView
#property (nonatomic, assign) id <DraggableToolbarViewDelegate> delegate;
#end
This is allowed as long as the name of the backing ivar in the subclass is different than that of the superclass, e.g.,
// In superclass
#synthesize delegate;
// In subclass
#synthesize delegate = delegate_;
Now change all the delegate messages in the two view classes to use this one property:
- (void)showBars
{
if (self.delegate)
{
[self.delegate ...
- (void)drag:(UIPanGestureRecognizer *)sender
{
//...
if (self.delegate)
{
[self.delegate ...
Now you can send setDelegate: to a DraggableToolbarView and it will use the same delegate for the dragging methods and the show/hide methods.
Finally, a terminology/explanatory note. In response to your previous question, Caleb used the correct term for "stacked" protocols, and Richard did not. Protocols don't inherit from each other, but one protocol can adopt the other. The relationship is similar, but distinct. When an object conforms to a protocol, it promises to implement the methods declared in that protocol. No implementation comes along with the protocol. The same is true of one protocol adopting the other -- the methods are just declared to exist in both. When you write:
#protocol DraggableToolbarViewDelegate <ToolbarViewDelegate>
you are saying that any object which promises to implement DraggableToolbarViewDelegate's methods will also implement the methods from ToolbarViewDelegate. That's all that it means. Again, no implementation comes along with that promise.
In this case, that means that a DraggableToolbarView can expect its delegate to implement the methods in ToolbarViewDelegate.
You have not given the entire code, but from whatever is out here,
Make sure that
Your ToolBarView and its subclasses have an id <ToolBarViewDelegate> delegate as a property.
Your DraggableToolbarViewDelegate extends NSObject protocol.
and your other ViewController object conforms to delegate protocol and not the toolbarview.
Once your controller gives implementation of delegates methods and conforms to the protocol, set the delegate of view's object to self and then use delegate property set in the view to call these protocol methods.

Call a ViewController method from NSObject Class

I am trying to call a method thats in my ViewController from a NSObject Class thats doing some parsing.
I initally call a connection class I have made wich downloads some data from my server, I then pass this data over to a parser class I have made, now what I am trying to do is pass this data back to the viewcontroller and reload the tableview thats in this view (thats on a navigation stack)
anyway this is causing some errors and I think it might be the way I am trying to call this method thats doing it. here is how I call it.
MyViewController *myViewController = [[MyViewController alloc] init];
[myViewController initFilterArray:filteredArray];
Now I think this is causing an issue because I am allocating a new viewcontroller object? is that right.. not to sure of the terminoligy.. but yea..
the result of which is that reloaddata is only calling
numberOfSectionsInTableView
tableView:numberOfRowsInSection
then thats it.
any help would be appreciated.
UPDATE:
so I am trying to set up a protocol/delegate to see if that fixes my problem.
so in my class.h this is what I am doing
#protocol PassParsedData <NSObject>
#required
- (void) sendMyArray:(NSArray *)modelArray;
#end
//..
id <PassParsedData> delegate;
//..
#property (strong) id delegate;
then in class.m
//..method
[[self delegate]sendMyArray:filteredArray];
//..
so thats my class, then over in my view controller where I want to call this sendMyArray I do this
viewcontroller.h
#import "class.h" //delegates & protocols
//..
interface VehicleSearchViewController : UITableViewController <PassParsedData> {
//..
then i call it like this
viewcontroller.m
//..
- (void)sendArray:(NSArray *)array
{
ICMfgFilterArray = array;
[self.tableView reloadData];
}
One way of doing this would be the recommended approach of delegates and protocols.
Your NSObject declares a protocol. The ViewController actually implements the protocol and sets itself as the delegate. Then the NSObject calls the method (not knowing who implements it). It is a loosely-coupled way to communicate between objects.
I actually recently wrote a blog post on a basic introduction to protocols and delegates if you're interested...
UPDATE
Based on your update above in question.
Don't forget to set your ViewController to be the delegate.
- (void)viewDidLoad {
// State that you will take care of messages from graphView (provided you have the protocol implementation!)
self.yourClass.delegate = self;
}
And the method in your ViewController should match the protocol signature. So in ViewController.m
- (void) sendMyArray:(NSArray *)modelArray {
ICMfgFilterArray = array;
[self.tableView reloadData];
}

Passing data between ObjectClass and ViewController

I am trying to pass some data back to my view controller from an object class.
This is a basic over view of what classes and views are doing, and then I will show you my code.
So ViewController, loads its tableviewcells. Then inside this delegate method it calles a connection class I have created, inside that conection class is NSURLConnection methods connecting and downloading data from the database, in the connectionDidFinishLoading method of this connection class I set up a parsing class and pass all of the downloaded data over to that.
Then I parse that data, and at the end of that parser inside parserDidEndDocument, I am trying to send the data that is now in an array variable back to my view controller to display. However.. for some reason my protocols and delegates are not working.
I have set up protocols inside m parser class and set the delegates in my view controller but it never makes it to my protocol method.
I will show you my code below.
parserclass.h
#protocol PassParsedData <NSObject>
#required
- (void)sendManufactureArray:(NSArray *)array;
#end
//..
id <PassParsedData> delegate;
//..
#property (strong) id delegate;
//
parserclass.m
#import "VehicleSearchViewController.h"
//..
#synthesize delegate;
//..
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//.. array stuff is set up and i can log it so i know its working.. i just want to show you the protocol and delegate stuff to be clear
[[self delegate]sendManufactureArray:filteredArray];
}
Then moving onto my view controller where I am hoping to call the protocol and get the filteredArray data back.
ViewController.h
#import "EngineResponses.h" //delegates & protocols
//..
#interface SearchViewController : UITableViewController <PassParsedData> {
//..
Viewcontroller.h
#import "EngineResponses.h"
//..
- (void)viewDidLoad
{
[super viewDidLoad];
//..
parserClass *pc = [[parserClass alloc] init];
[pc setDelegate:self];
//..
}
- (void)sendManufactureArray:(NSArray *)array //Breakpoint here is never accessed
{
FilterArray = array;
[self.tableView reloadData];
}
As you can see in that last method which is the protocol I am calling, its never accessed by the thread. I have checked, This call
[[self delegate]sendManufactureArray:filteredArray];
gets accessed fine.. but it just never makes it back to the View Controller.. any ideas... am I missing anything? .. im at a complete loss, been working on this all day.
any help would be HUGELY appreciated! :)
UPDATE:
I have added this to my ViewController.h
//..
ParserClass *parserclass;
//..
#property (strong, nonatomic) ParserClass *parserclass;
//..
viewcontroller.m
#synthesize parserclass;
//..
//then I call this in viewdidload
[engineResponses setDelegate:self];
As others have said in the comments, your pc variable is being deallocated at the end of the viewDidLoad block, since the only reference it has goes out of scope there. If you want it to live on, you must enlarge its scope (i.e. make it an instance variable).

A question of objective-C protocol

I try to learn protocol of objective C.
I write two files, the first one is FirstViewController.h, and in which there is a protocol "print". I declare FirstViewController class in successViewController with the delegate method "print".
The question is why the console output is "C". Why I can not get the "B" output? Why the protocol method did not perform?
#import <UIKit/UIKit.h>
#import "FirstViewController.h"
#interface successViewController : UIViewController <FirstViewControllerDelegate> {
}
#end
#import "successViewController.h"
#import "FirstViewController.h"
#implementation successViewController
- (void)viewDidLoad {
FirstViewController *firstViewController= [[FirstViewController alloc] init];
firstViewController.delegate=self;
NSLog(#"C");
[super viewDidLoad];
}
-(void) print{
NSLog(#"B");
}
#end
#import <Foundation/Foundation.h>
#class FirstViewController;
#protocol FirstViewControllerDelegate <NSObject>
- (void) print;
#end
#interface FirstViewController : NSObject {
id <FirstViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id <FirstViewControllerDelegate> delegate;
#end
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize delegate;
#end
Because you never call the print method. Where were you expecting it to be called?
Objective-C protocols allow you to specify that a class is capable of performing certain actions. In your example, the successViewController is declared FirstViewControllerDelegate, meaning it is capable of handing the duties required by FirstViewController of its delegate. It is more of a programming contract between classes, one that can be verified by the compiler.
As a side note, classes in Objective-C should always start with a capital letter, methods should always start lowercase. Your FirstViewController follows this rule, but the successViewController does not.
You need to call the method you want to use.
[successViewController print];
You never call the delegates print method. A delegate can not read your mind and automagically call stuff. Lets take a small example how how delegates are supposed to work.
Assume we have a class called Delay, the only thing it do is to wait for a time when start is called, and then tell it's delegate that it has waited. Optionally the delegate can tell the Delay how long to wait, if the client do not care, a 1 second delay is assumed.
Some rules:
First argument of all delegate methods should be the sender itself, never have delegate methods with no arguments.
Delegate method name should include one of the words:
will - if method is called before something unavoidable occurs. Example applicationWillTerminate:
did - if method is called after something has occurred. Example scrollViewDidScroll:
should - if the method return a BOOL to signal if something should occur. Example textFieldShouldClear:
Name the method to tell what has occurred, not what you expect the delegate to do.
Only exception is if the client is expected to return something, then that something should be part of the name. Example: tableView:editingStyleForRowAtIndexPath:
Here is the simple definition and implementation. Notice that I do not even check if the delegate has been set, since calling methods on nil is just ignored anyway.
// Delay.h
#protocol DelayDelegate;
#interface Delay : NSObject {
#private
id<DelayDelegate> _delegate;
}
#property(nonatomic, assign) id<DelayDelegate> delegate;
-(void)start;
#end
#protocol DelayDelegate <NSObject>
#required
-(void)delayDidComplete:(Delay*)delay;
#optional
-(NSTimeInterval)timeIntervalForDelay:(Delay*)delay;
#end
// Delay.m
#interface Delay
#synthesize = delegate = _delegate;
-(void)start {
NSTimeInterval delay = 1.0;
if ([self.delegate respondsToSelector:#selector(timeIntervalForDelay:)]) {
delay = [self.delegate timeIntervalForDelay:self];
}
[self performSelector:#selector(fireDelay) withObject:nil afterDelay:delay];
}
-(void)fireDelay {
[self.delegate delayDidComplete:self];
}
#end

how to extend a protocol for a delegate in objective C, then subclass an object to require a conforming delegate

I want to subclass UITextView, and send a new message to the delegate. So, I want to extend the delegate protocol. What's the correct way to do this?
I started out with this:
interface:
#import <Foundation/Foundation.h>
#class MySubClass;
#protocol MySubClassDelegate <UITextViewDelegate>
- (void) MySubClassMessage: (MySubClass *) subclass;
#end
#interface MySubClass : UITextView {
}
#end
implementation:
#import "MySubClass.h"
#implementation MySubClass
- (void) SomeMethod; {
if ([self.delegate respondsToSelector: #selector (MySubClassMessage:)]) {
[self.delegate MySubClassMessage: self];
}
}
#end
however with that I get the warning: '-MySubClassMessage:' not found in protocol(s).
I had one way working where I created my own ivar to store the delegate, then also stored the delegate using [super setDelegate] but that seemed wrong. perhaps it's not.
I know I can just pass id's around and get by, but My goal is to make sure that the compiler checks that any delegate supplied to MySubClass conforms to MySubClassDelegate protocol.
To further clairfy:
#interface MySubClassTester : NSObject {
}
#implementation MySubClassTester
- (void) one {
MySubClass *subclass = [[MySubClass alloc] init];
subclass.delegate = self;
}
#end
will produce the warning: class 'MySubClassTester' does not implement the 'UITextViewDelegate' protocol
I want it to produce the warning about not implementing 'MySubClassDelegate' protocol instead.
The UITextView defines its delegate as
#property(nonatomic, assign) id<UITextViewDelegate> delegate
meaning it conforms to UITextViewDelegate, and that's what compiler checks. If you want to use the new protocol, you need to redefine delegate to conform to your protocol:
#interface MySubClass : UITextView {
}
#property(nonatomic, assign) id<MySubClassDelegate> delegate
#end
The compiler shouldn't give any more warnings.
[Update by fess]
... With this the compiler will warn that the accessors need to be implemented... [I implemented this:]
-(void) setDelegate:(id<MySubClassDelegate>) delegate {
[super setDelegate: delegate];
}
- (id) delegate {
return [super delegate];
}
"
[My update]
I believe it should work if you only make a #dynamic declaration instead of reimplementing the method, as the implementation is already there:
#dynamic delegate;
For anyone still interested, this can be done quite simply like this (for sake of the example, I subclass UIScrollView):
#protocol MySubclassProtocol <UIScrollViewDelegate>
#required
-(void)myProtocolMethod;
#end
#interface MySubClass : UIScrollView
#property (nonatomic, weak) id <MySubclassProtocol> delegate;
The most important detail here is the part between the <> after your protocol's name which, put in a simple manner, signals you're extending that protocol.
In your implementation, all you need to do then is:
#synthesize delegate;
And you're done.
You need to extend the super protocol:
#protocol MYClassProtocol <SuperClassProtocol>
-(void)foo;
#end
after that DON'T (!!!) create the #property for the delegate otherwise you override the original delegate object, but simply override the method:
- (id<MYClassProtocol>)delegate
{
return (id<MYClassProtocol>)[super delegate];
}
now you can use the delegate in the classic way:
[self.delegate foo];
[self.delegate someSuperClassDelegateMethod];
Given that MySubClassMessage: is optional, you should be able to simple do a simple:
- (void) SomeMethod {
SEL delegateSelector = #selector(MySubClassMessage:);
if ([self.delegate respondsToSelector:delegateSelector]) {
[self.delegate performSelector:delegateSelector withObject:self];
}
}
The complier should still check that the implementing class conforms to your protocol (or at least claim to in the header) and you won't get the error you described.