This is the delegate
#protocol DropControllerDelegate;
#interface DropController : NSObject
id<DropControllerDelegate> delegate;
}
#property (nonatomic, assign) id<DropControllerDelegate> delegate;
+ (DropController*) sharedController;
#protocol DropControllerDelegate <NSObject>
- (void)openUserButtons;
- (void)startUpload;
- (void)uploadDone;
- (void)uploadFailed;
- (void)startDownload;
- (void)downloadDone;
- (void)subFolderLoaded;
#end
This is the singleton code:
static DropController *sharedCont = nil;
#pragma mark Singleton stuff
+ (DropController *) sharedController {
#synchronized(self) {
if (!sharedCont)
sharedCont = [[DropController alloc] init];
return sharedCont;
}
return sharedCont;
}
The code to set the delegate is (in both myControllerA and myControllerB):
DropController* dropHelper = [DropController sharedController];
dropHelper.delegate = self;
I'm able to receive the calls in one controller but not in the other controller (the code is a copycat), this is driving me crazy!
As i said in my comment, since you are using a shared instance of that object, it will overwrite the previously set delegate to the new object. So i would suggest to hold a array in your sharedController. Add objects to that array which will want to become the delegates to the sharedController.
Then iterate through that array and call the method over each object in it. Its pretty simple.
Edit:
When you assign the delegate in your viewcontroller A with the statement dropHelper.delegate = self; object A becomes the delegate. Calling the method [delegate openUserButtons]; will trigger the method in viewcontroller A. But when you do dropHelper.delegate = self; in viewcontroller B, [delegate openUserButtons]; will call the method in object B. It will not call both the methods from a and b. Since there is only one delegate variable and you are using a shared singleton object.
Related
I want to invoke a delegate in class method.
The example below obviously does not work, since the delegate is an instance variable that is accessed within a class method. (Error: instance variable 'delegate' accessed in class method)
Is there an alertnative?
My header file:
// MyClass.h
#import <Foundation/Foundation.h>
#protocol MyDelegate <NSObject>
-(void)update;
#end
#interface MyClass : NSObject
{
id<MyDelegate> delegate;
}
#property (nonatomic, retain) id delegate;
+(void)methodThatInvokesDelegate;
#end
My implementation file:
// MyClass.m
#import "MyClass.h"
#implementation MyClass
#synthesize delegate;
+(void)methodThatInvokesDelegate{
[delegate update];
}
#end
Three obvious options:
Singleton
Static variable (i.e., class variable) pointing to the delegate
Use NSNotification's rather than delegates
Since a singleton (and a static variable) can't keep track of the lifecycle of delegates, I think option three would be the cleanest.
I want to know the context, which let you run in that situation. ;-) Anyway:
First: Delegates are set for a specific instance object. Because of this, you can have different delegates for different instances of the same (delegating) class.
Second: A class method runs inside a class object of that class. This is an object that is different from every instance object of that class. So there is nothing that can be called "the delegate". You can have 100s of delegates.
Third: Your class object needs a delegate at its own. So you have to add a property delegate to the class object and then use this. (Yes, it is possible to have properties an a class object. I did not write declared property.) If you need further information on how to do this, just comment it. I will add code.
I'm not sure if this will help you, but I have a similar situation where I have a class method used for data loads. In this case, the class instantiates itself (so that the caller doesn't need to) until it is done. (this code was edited somewhat to make it work here)
header file:
#protocol DataLoaderDelegate2 <NSObject>
- (void) dataLoaderSuccess:(NSData *)data loader:(id)theloader;
- (void) dataLoaderFailed:(NSString *)error loader:(id)theloader;
#end
#interface DataLoader2 : NSObject {
NSURLConnection *conn;
NSMutableData *receivedData;
NSFileHandle *fileHandle;
id <DataLoaderDelegate2> delegate;
}
#property (nonatomic, assign) id<DataLoaderDelegate2>delegate;
Call to start the process - the call to initWithRequest passes "self" along.
+ (DataLoader2 *)loadWithURLRequest:(NSURLRequest *)req delegate:(id)_delegate
{
DataLoader2 *dl = [[DataLoader2 alloc] init];
[dl setDelegate:_delegate];
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
return dl;
}
When the data is done loading, it cleans up with something like
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([delegate respondsToSelector:#selector(dataLoaderSuccess:loader:)])
[delegate dataLoaderSuccess:(fileHandle)?(id)fileHandle:(id)receivedData loader:self];
[self autorelease];
}
I am working on a splitView application for my iPad. I have implemented a UIButton called as Upload. On clicking on it, a UITableView appears inside a UIPoverController. On clicking on any of the contents, I want to display some respective site in my UIwebView in UIDetailView. For this I have implemented a delegate method protocol. I have used the following lines of code in UploadTableViewController.h file::
#protocol UploadTableViewDelegate <NSObject>
#required
- (void)selected:(NSString *)his;
#end
#interface UploadSpaceTableViewController : UITableViewController{
id<UploadSpaceTableViewDelegate> delegate;
}
#property (retain) id delegate;
#end
In the corresponding .m file I have used the following lines of code ::
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (delegate != nil) {
NSString *hisSelected = [keys objectAtIndex:indexPath.row];
NSLog(#"%# lolwa", hisSelected);
[delegate selected:hisSelected];
}
}
in the .m file of class where I have implemented the function Selected, the code is ::
- (void)selected:(NSString *)Key {
NSLog(#"hello");
[self.UploadSpaceTableViewPopover dismissPopoverAnimated:YES];
}
-(IBAction)uploadpressed:(id)sender{
Upload.delegate = self;
self.Upload = [[UploadSpaceTableViewController alloc]
initWithStyle:UITableViewStylePlain];
self.UploadTableViewPopover = [[UIPopoverController alloc]
initWithContentViewController:UploadSpace];
[self.UploadTableViewPopover presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
However, I am unable to get hello (written in the function Selected) NSLogged in gdb. This is the first time that I am using this delegate method protocol. I am unable to sort this out. Can someone help me out ? Thanks and regards.
[delegate keySelected:hisKeySelected]; is your first problem. You don't declare a delegate method named -keySelected:, you declare a delegate method named -Selected:.
Your second problem is the fact that you are most definitely not the delegate of your table view. In order for a delegate method like -didSelectRowAtIndexPath: to be called, you must be the table's delegate.
PS, don't begin instances, or method names, with an uppercase letter. In ObjC, uppercase letters indicate a class.
EDIT: this is what your UploadSpaceTableViewController header should look like:
#protocol UploadTableViewDelegate <NSObject>
#required
- (void)selected:(NSString *)his;
#end
#interface UploadSpaceTableViewController : UITableViewController<UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, assign) id <UploadSpaceTableViewDelegate>delegate; //delegates are weak!!!
#end
And the .m, I will skip a lot of the unnecessary stuff:
-(void)viewDidLoad {
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
}
//other code
Furthermore, your delegate is declared retain, which is an absolutel No-No in ObjC. Declare is weak if using ARC, or assign if not.
You are also producing a nil delegate in in your -uploadPressed: method by setting it before you explicitly own or initialize the object. Here's how it should look:
self.Upload = [[UploadSpaceTableViewController alloc]initWithStyle:UITableViewStylePlain];
Upload.delegate = self;
Delegation works like this
declare a protocol - you have done this
declare a delegate property - you have done this
In the class which you want to be the delegate say it conforms to the protocoll
#interface MyClass : MySuperClass <UploadTableViewDelegate>
set the delegate property so the delegate class can get the delegate messages
uploadSpaceTVC.delegate = self;
call the delegate methods in your non delegate class (UploadSpaceTableViewController)
[self.delegate selected:#"test"];
As a new iOS developer, I have finally stumbled across delegates. I'm trying to follow a tutorial: http://gabriel-tips.blogspot.com/2011/05/input-accessory-view-how-to-add-extra.html, But I'm having difficulty understanding where I am supposed to put the actual delegate methods.
Secondly, would anyone mind providing a dumbed down explanation of how a delegate method is invoked?
Thanks!
A delegate is simply a class that agrees to do work for another class. The delegate methods are invoked by the delegating class. The delegate must therefore, provide an implementation of the appropriate method. Let's make a simple view controller with a table view.
// MyViewController.h
#interface MyViewController : UIViewController <UITableViewDelegate>
#property (nonatomic, retain) UITableView *myTableView;
#end
Here in the MyViewController.h file I have declared my view controller to be a delegate of type UITableViewDelegate (it really means it implements the UITableViewDelegate protocol. More on this later). I have thus agreed to respond to requests to my view controller. The requests will come from the table view called myTableView. However, simply stating that I adhere to UITableViewDelegate does not make my view controller a delegate of anything. I must specify that directly:
// MyViewController.m
#import "MyViewController.h"
#implementation MyViewController
- (void)loadView
{
myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
myTableView.delegate = self;
self.view = myTableView;
}
#end
Here I specifically set MyViewController to be the delegate of myTableView. Now whenever the table view wants to ask its delegate to do something, it will send that message to my view controller. Thus, MyViewController MUST provide implementations of the appropriate delegate methods:
// MyViewController.m
#import "MyViewController.h"
#implementation MyViewController
- (void)loadView
{
myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
myTableView.delegate = self;
self.view = myTableView;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Selected section:%i row:%i", indexPath.section, indexPath.row);
}
#end
Here I have provided an implementation for the delegate method tableView:didSelectRowAtIndexPath: which will be called by myTableView when it is appropriate (the user selects a row).
Here you can find all the delegate methods defined in UITableViewDelegate. Some are required and others are optional:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewDelegate_Protocol/Reference/Reference.html
In order to be a delegate of a class you should know which methods you are required to provide implementations for.
If you wanted to create your own delegate definitions, you would create a new protocol. You do not retain your delegates (see the property declaration), as this creates a retain cycle:
// MyViewController.h
#class MyViewController;
#protocol MyViewControllerDelegate
- (void)viewController:(MyViewController *)viewController didChangeSelection:(NSIndexPath *)newIndexPath;
#end
#interface MyViewController : UIViewController <UITableViewDelegate>
#property (nonatomic, retain) UITableView *myTableView;
#property (nonatomic, assign) id<MyViewControllerDelegate> delegate;
#end
Here we have created a new protocol. Any class that wants to be respond to the viewController:didChangeSelection: message could now do so. Just like with the table view above it would set the delegate to itself and then implement the method. Now that you have a delegate, you can invoke the method at an appropriate time.
// MyViewController.m
#import "MyViewController.h"
#implementation MyViewController
- (void)loadView
{
myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
myTableView.delegate = self;
self.view = myTableView;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Selected section:%i row:%i", indexPath.section, indexPath.row);
indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
[self.delegate viewController:self didChangeSelection:indexPath];
}
#end
Now the delegate can receive the message and do what it wants knowing that my view controller changed the selection.
A delegate pattern is a convenient way to allow for the communication between independent controller that allows for loose coupling. So let's say you have a pattern like this:
A
/ \
B C
Where A instantiates B and C. Communicating between A to B and A to C are easy but how would you communicate between B and C? B to A? C to A? There are a couple different ways you could do so such as Key-Value Observing or Block Callbacks. Delegation, though, are still most frequently used although Blocks are coming on strong.
In this example, object A instantiates object B to create an object and fill it with info. How would object B pass the new object back to A as you want to keep things loose? Well, with these 9 easy steps, you can do it too! It may not make sense but we'll start with ClassB…
// ClassB.h
#protocol ClassBDelegate; //(1)
#interface ClassB : NSObject
#property (nonatomic, weak) id<ClassBDelegate>bDelegate; //(2)
-(void)makeNewObjectAndSendBack;
#end
#protocol ClassBDelegate : NSObject //(3)
-(void) classB:(Class B *)theClassB finishedWithObject:(id)finishedObject; //(4)
#end
ClassB.m
#implementation
#synthesize bDelegate = _bDelegate; //(5)
-(void)makeNewObjectAndSendBack {
//something something something
[self.bDelegate classB:self finishedWithObject:newObject]; //(6)
}
#end
define the protocol that will be established later
set an instance of an object that will conform to that protocol
set up the protocol
set up the method call that you'll use to send the finishedObject back to A.
synthesize the delegate
after you do what you need to do, you send it back using the method
you defined in 4
// ClassA.h
#interface ClassA : NSObject <ClassBDelegate> //(7)
#property (nonatomic, strong) ClassB theClassB;
-(void)yourMethodToDoSomething;
#end
ClassA.m
#implementation
#synthesize theClassB = _theClassB;
-(void)randomMethod {
self.theClassB = [ClassB new];
self.theClassB.bDelegate = self; //(8)
[self.theClassB makeNewObjectAndSendBack];
}
-(void) classB:(Class B *)theClassB finishedWithObject:(id)finishedObject { //(9)
[self doSomethingWithFinishedObject:finishedObject]; //ta-da!
}
#end
7.Conform to the ClassBDelegate protocol. This basically says that you
will implement the methods defined in the protocol definition.
8.Set the classB object's delegate object as self! This is crucial and
often skipped.
9.Implement the delegate method for when you get the new object back.
So the process, in short is: A instanciate B. A sets B's delegate as self. A tells B to do something. B does something and sends object back via delegate method. A gets it back.
For more information, including what you can do with protocols, check out:
Big Nerd Ranch talk about Protocols
Part 1
Part 2
Part 3
Good luck!
It seems you might be a little confused as to what delegates are and how they are used. Here are two links to Apple documentation you might find useful: A conceptual overview and a more in depth explaination.
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];
}
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).