iPhone - NSObject getting reference to viewController - iphone

I have this object of NSObject class. This object is shown on a view managed by a viewController. How do I get a reference to that viewController from inside the object's class?

There is no "myViewController" property as you know. The easiest way to give any object access to some other object is through a delegate relationship.
Define a protocol for the delegate - typically in the module that wants access to the object which will be the delegate, i.e. the view controller
#protocol MyViewControllerDelegate
- (void)someActionTheViewControllerWillDo;
#end
Advertise the delegate support in the class implementing it
#interface MyViewController : UIViewController <MyViewControllerDelegate>
...
#end
Implement the function you defined as being part of the protocol in the view controller:
#implementation MyViewController
etc. etc.
#pragma mark -
#pragma mark MyViewControllerDelegateMethods
- (void)someActionTheViewControllerWillDo
{
NSLog(#"I'm being called from an object that has me as a delegate");
}
etc. etc.
#end
Make a variable in the calling object to store the delegate object
#interface MyObject : NSObject
{
etc. etc.
id<MyViewControllerDelegate> myDelegate;
etc. etc.
}
Initialize that object
MyObject* myObject = [[MyObject alloc] initWithblahblah...
myObject.myDelegate = self
/* assuming myObject is being created in the view controller... */
In myObject - use the defined protocol to access methods in the delegate object!
[myDelegate someActionTheViewControllerWillDo];

User delegate pattern:
0 . Declare a protocol:
#protocol My_Object_Delegate;
1.Give your NSObject an instance variable:
id <My_Object_Delegate> delegate;
2 . Set this delegate the view controller that supervise it:
myObject.delegate = myViewController;
3 . When your NSObject is done. Let it ask its delegate to perform certain task:
[myObject.delegate performaCertainTask:self];

Related

Access delegate methods of UIPageViewController when you've created a protocol

I'm using the UIPageViewController and I've made my own protocol like this:
#protocol MyDataDelegate <NSObject, UIPageViewControllerDelegate>
- (void)recieveData:(NSString *)theData;
#end
How can I set the delegate of UIPageViewController to self so I can use those delegate methods? The normal code for this would be self.delegate = self; but since I've made another delegate it gives me a warning "Assigning to 'id<MyDataDelegate>' from incompatible type 'PageScrollViewController *const_strong'" I want to set this to self so I can access the delegate methods of the UIPageViewController
Your subclass eclipses delegate property of UIPageViewController. Give your delegate property some other name, for instance: #property (nonatomic,weak) id myDelegate;
Have you declared your PageScrollViewController class to conform to MyDataDelegate? You can either do this in the main #interface declaration:
#interface PageScrollViewController : UIPageViewController <MyDataDelegate>
// ...
#end
Or in the class category in your .m file:
#interface PageScrollViewController () <MyDataDelegate>
// ...
#end

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];
}

protocol method is not being called by the delegate object

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.

Delegate works in controller A but not in controller B

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.