Creating an object to act as a delegate - Objective C - iphone

My question is simple actually, how do I create an object to act as a delegate, instead of including the delegate methods in my view?
For example, I have x functionality that requires delegate methods, and they're currently setup to use self as the delegate. I'd like to put those methods in their own object so that the delegate methods can be called and do stuff if the view has ended.
What's the best way?

for example, NSXMLParser delegate methods - they exist, the delegate is defined, but I dont want to call them as self in my view controller... what other option do I have?
You can specify another custom class to handle the delegate methods, if you wish. Simply create a class, call it MyXMLParserDelegate or something similar. Then, all you have to do is tell your NSXMLParser object that it should use an instance of your class as its delegate.
If you are using Interface Builder, add a new object to the XIB file, set its class to MyXMLParserDelegate, and then drag a connection from your NSXMLParser object's delegate selector to the new object.
If you are doing it programmatically, the basic operation looks like this:
MyXMLParserDelegate * myDelegate = [[MyXMLParserDelegate alloc] init];
[someXMLParser setDelegate:myDelegate];
Keep in mind, however, that delegates are not retained, so in order to do this without leaking memory, you should add an ivar of type MyXMLParserDelegate to your viewController class, and then do the following:
// in your #interface block:
{
...
MyXMLParserDelegate * myDelegate;
}
// in your init method:
myDelegate = [[MyXMLParserDelegate alloc] init];
// in your awakeFromNib method (or anywhere else it seems appropriate):
[someXMLParser setDelegate:myDelegate];
// in your dealloc method:
[myDelegate release];

Check out this answer, I think it covers what you need: How to use custom delegates in Objective-C

Related

2 delegates of one class

I use delegates to run some methods.
I got class webrequests with 2 delegates: menuVC and mapVC.
When I in mapVC webrequests is accomplish delegates methods of mapVC class.
When I in menuVC webrequests is tried to accomplish delegates methods of mapVC class and crashed app.
Method in webrequests do not helps
if ([self.delegate isKindOfClass: [MenuViewController class]])
{
self.delegate = [MapViewController class];
}
Why it happens?
I use in both classes
self.webRequests = [WebRequests sharedInstance];
self.webRequests.delegate = self;
Original answer:
You can only have one delegate of an object at one time, unless the object is designed to allow for different delegate protocols (e.g. UITableView has both a "delegate" AND a "datasource").
You also can not set your delegate to a non-instantiated object like what you are doing on this line:
self.delegate = [MapViewController class];
This needs to be an actual allocated and instantiated object.
Like "self.mapViewController" that you just pushed or created.
For this question, you probably need to better explain what you are ultimately trying to do, since it looks like your current delegate is a MenuViewController object and you're trying to switch the delegate to a MapViewController object.
New answer:
Since you want things to happen in two different view controllers, the best way to do what you want to do is use a "NSNotification" (which allow multiple objects to observe -- or watch -- for things happening).
Here is a tutorial you can look at, to get a good start with it.

Repeated Code for multiple viewcontrollers

I need to use the same set of code in 4 view controllers. I am writing this code in -(void)viewWillAppear.
Is there any possibility that I can write this code once and use it in all 4 view controllers?
You could make a subclass of UIViewController with the common code, and then change each of your existing UIViewController subclasses to be a subclass of that new class.
You can create a static class and call the method from there:
#interface myClass : NSObject
+(void)myMethod{
#end
+(void)myMethod{
//Do my stuff
}
And then you call the method from wherever you want:
[myClass myMethod];
Write the code in viewWillAppear in a custom class which subclass of UIViewController.
Then create that 4 classes by subclassing of your custom class.
And call [super viewWillAppear].

What's the Best Way to Send Parameters to a UIViewController?

I ask this question because it appears that viewDidLoad gets called before the main block of the initializer does and the class variables I'm initializing in the initializer are turning up nil in viewDidLoad. For your reference, I'm doing this entire viewcontroller programmatically and I've created a custom initializer so I can take in various parameters to be used in my viewcontroller. My custom initializer calls UIViewControllers designated initializer of course.
Basically, I'm curious about what is the proper design pattern for sending in parameters to a UIViewController? I've read other threads about this and haven't really gotten a definitive answer. Should I just skip the initializer and set the properties manually (from outside the class)? That seems kind of bleh, I'd really like to send in some parameters and am curious how others go about doing this?
The reason viewDidLoad is called before initialization completes, is probably because you call the view method in the initializer. For example:
- (id)init
{
if ((self = [super init])) {
_thing = 123;
_other = self.view.frame.size.width / 2;
}
return self;
}
viewDidLoad is called when the view loads. And the view loads as soon as you call the view method (or access the view property, if you prefer). So you should avoid referencing the view in init.
To answer your question, I prefer to create an init method for my view controllers.
- (id)initWithThing:(MyThing *)thing thang:(MyThang *)thang
{
if ((self = [super init])) {
_thing = [thing retain];
_thang = [thang retain];
// ...
}
return self;
}
You can also use properties to set extra variables after initing. Personally I prefer to do this with optional properties only, though, and put required properties in the init method. That way I can't init the view controller with an invalid state.
I encapsulate the state of my controllers in an additional state object. So the controller usually has ivars for the GUI elements and a reference to this state object.
State objects are handled by a StateManager object on my delegate. So instead having a controller referencing another controller and set variables directly, all changes go through this manager. A little more work but way less messy.
Any class is able to retrieve the state for any other controller and change it. This is the purpose of some controllers (eg: choosing a video from youtube happens on a dedicated controller). But usually is just one class getting a state to push the next controller with initWithState:. The pushed controller then applies the state to its GUI in viewDidLoad or changes this state object passed from the previous class.
The StateManager keeps a dictionary of all the state objects. I keep the state object graph light, eg: I store a reference to a image, but not the image itself. The real beef of the application is in Core Data, I only use all this to handle the GUI state. The StateManager listens for the application resign event and saves the state dictionary to disk using NSCoding. The state object ivars are always nil or some meaningful value, no dangling pointers.
I'm working on my 2nd iPhone app and this seems to be working, but I wonder too how other people does it. Any input is welcome.
Basically you should have properties defined for your input data but add a custom init-function.
If you create a custom init-Method you should be fine - remember that initWithNibName:bundle: is the main initializer of UIViewController so this is what you want to call from your custom init-Method. viewDidLoad will always be called after your init-Method at the first usage of customVC.view (either from your code or via Framework):
- (id)initWithDataObject:(MyDataObject*)obj
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.dataObj = obj;
}
return self;
}

iOS - Passing Values from an Object to it's Containing Class

The setup:
I have an AppDelegate and declared on that is CustomUIViewController.h and in that controller I have RandomName.h declared (as an object, not a subclass) can I use [super methodName] or similar to trigger a method on CustomUIViewController from a method on RandomName.h?
Or do I have to pass it to the appDelegate and then from there to CustomUIViewController? (How I have been doing it)
Thanks
P.S. Coffee is good.
I think I've understood your question. Pardon me if I didn't ;-)
super doesn't work that way. You can simply call,
[appDelegate.customViewController methodName];
The other way is to pass the reference of the customViewController to RandomName object, something like,
[[RandomName alloc] initWithParent:self];
You have to keep the reference of self in initWithParent method, lets say the variable name is parent, and call the method like this,
[parent methodName];

Whats the best place to set a View Controller ivar?

I have an XML reader class which I initialize with a URL
- (id)initWithURL:(NSURL *)url
This class adds objects to an array in the calling class using an instance variable
// in the interface
ViewController *viewController;
// in the implementation
[viewController addObject:theObject];
Now, I initialize my XML reader class, then set the View Controller separately:
XMLController *xmlController = [[XMLController alloc]
initWithURL:url];
xmlController.viewController = self;
My question is whether I should create a new init function which sets the viewController at the same time.
Thanks.
Edit: I forgot to add that my XML reader starts downloading and parsing the class in the init function.
It's entirely up to you. You can see examples of both styles all over Apple's code.
As long as you don't make any assumption about the viewController property's value being constant over time, it should be fine to leave it as-is.
BTW, you might think about refactoring the addObject: logic into a protocol instead of requiring a specific subclass. Something like:
-xmlController:didDecodeObject:
Or whatever makes sense for your XMLController object's logic.
If your init routine is going to cause delegate/controller calls, or set off asyncronous activities (potentially including your downloading) that could message the delegate, then you should include it in the init function.
Otherwise your controller might miss potential delegate messages such as xmlController:didStartConnection that might be called before your initWithURL routine returns.
Also, if the controller/delegate is a required part of the XMLController activities, then you should include it in your init routine.
So yes, in this case I would suggest:
XMLController *xmlController = [[XMLController alloc] initWithURL:url andController:self];