Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Mockup & CodeGen, iPhone & iPad
($9.99)

Make your own iPhone apps
and run them live!
(free)

Manu
($0.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 10-15-2009, 03:09 PM   #1 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Default Get the current controller from the view...

I'm trying to build some reusable UI elements with functionality (kind of like the slider or switch), and I'm wondering if there is a way to get a view's controller. I feel like this is either really easy and I will kick myself, or Apple doesn't want you to do it.

What I'd like to be able to do is have a UIView subclass that can present a modal view controller, set itself as the delegate, and take care of any necessary details. It will hand relevant info back to its view controller after everything is done.

My current solution is to declare a
UIViewController *controller;
and initialize with a custom method:
initWithFrame: andController:
Then I can present the modal view controller thus:
[self.controller presentModalViewController:stuff animated:YUPPEROONIE];

While I understand MVC, I think there are occasions to use more "grassroots" code (decentralized? I'm self-taught and don't know the right lingo). I'd also be very interested in your opinions of whether this is a good or bad idea, because maybe there's something I'm not thinking of.

Thanks as always!
jazztpt is offline   Reply With Quote
Old 10-15-2009, 03:19 PM   #2 (permalink)
Humbled Student
 
Dutch's Avatar
 
Join Date: Apr 2009
Location: Long Island, NY
Age: 32
Posts: 883
Send a message via AIM to Dutch
Default

Your reusable objects should have a "myDelegate" property (of type id), or something similar. When you initialize the object you would also need to set the delegate


Code:
MyObject *o=[[MyObject alloc] init];
[o setMyDelegate:self];
...
Then in your object(s), you can use the following method to determine the type of object it is...

Code:
if ([myDelegate isKindOfClass:[UIViewController class]]){
  //take appropriate steps
} else if ([myDelegate isKindOfClass:[WeirdCustomObject class]]){
  //take appropriate steps
}
Dutch is offline   Reply With Quote
Old 10-15-2009, 04:02 PM   #3 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Default

Quote:
Originally Posted by Dutch View Post
Your reusable objects should have a "myDelegate" property (of type id), or something similar. When you initialize the object you would also need to set the delegate


Code:
MyObject *o=[[MyObject alloc] init];
[o setMyDelegate:self];
...
Then in your object(s), you can use the following method to determine the type of object it is...

Code:
if ([myDelegate isKindOfClass:[UIViewController class]]){
  //take appropriate steps
} else if ([myDelegate isKindOfClass:[WeirdCustomObject class]]){
  //take appropriate steps
}
Hi Dutch,

You are Da Man on these forums! Always with the quick, clear, helpful replies.

I've used delegation, but only in the context of sending back messages. I wasn't sure you could call a regular method (non-delegate method) on the delegate...but then again, it's just a pointer to an object, so why not?

That's a great idea, I'm going to try it.
Thanks!
jazztpt is offline   Reply With Quote
Old 10-15-2009, 04:04 PM   #4 (permalink)
Humbled Student
 
Dutch's Avatar
 
Join Date: Apr 2009
Location: Long Island, NY
Age: 32
Posts: 883
Send a message via AIM to Dutch
Default

Quote:
Originally Posted by jazztpt View Post
Hi Dutch,

You are Da Man on these forums! Always with the quick, clear, helpful replies.

I've used delegation, but only in the context of sending back messages. I wasn't sure you could call a regular method (non-delegate method) on the delegate...but then again, it's just a pointer to an object, so why not?

That's a great idea, I'm going to try it.
Thanks!
I rarely use the delegate method model, unless my object is really complex. Essentially you are accomplishing the same thing. There may be actual differences, but I have no idea what they are.

Thanks for the kind words.
Dutch is offline   Reply With Quote
Old 10-15-2009, 04:07 PM   #5 (permalink)
Humbled Student
 
Dutch's Avatar
 
Join Date: Apr 2009
Location: Long Island, NY
Age: 32
Posts: 883
Send a message via AIM to Dutch
Default

Actually, now that I think it through a little bit more you might not even need to check the type of object myDelegate is... you can probably just do...

Code:
if ([myDelegate respondsToSelector:@selector(methodName:)])
    [myDelegate methodName:object];

if ([myDelegate respondsToSelector:@selector(methodName2:)])
    [myDelegate methodName2:object];

(not at my mac, so this code may not be 100%)
Dutch is offline   Reply With Quote
Old 10-15-2009, 06:12 PM   #6 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Talking

Quote:
Originally Posted by Dutch View Post
I rarely use the delegate method model, unless my object is really complex. Essentially you are accomplishing the same thing. There may be actual differences, but I have no idea what they are.

Thanks for the kind words.
This approach worked like a charm.
Thanks!

(oo, how I love cool reusable decentralized code! woo!)
jazztpt is offline   Reply With Quote
Old 10-21-2009, 11:10 PM   #7 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Default

After using this for a bit, I ended up going back to my original idea (mostly). Using the delegate when you're not looking for any delegate protocol callbacks is a bit tricky -- you get lots of warnings.

My real goal here was to be able to access the current/owning view controller to present a modal view controller. So what I did was declare a UIViewController object that I called viewController (I could have also declared my subclass) as a property in the widget (using assign). When I created the widget from my view controller, I simply passed self into that property like this:

Code:
QuestionView * newQuestionView = [[[QuestionView alloc] init] autorelease];
newQuestionView.viewController = self;
This appears to work perfectly well without any warnings. Anybody think of a reason to do it differently?
jazztpt is offline   Reply With Quote
Old 10-22-2009, 12:10 AM   #8 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 495
Default

Nope, that's actually exactly what I do. Considering that the framework kind of enforces separation of concerns (which is fine), I find it a bit annoying that UIViewController *controller isn't automatically a property on UIView inherently, and thusly I have to declare it every time. Especially considering that controllers have a UIView *view property.

Anyway, I also use this method anytime I have interactions, so the controller handles the behaviors - all selectors happen on the self.controller and then the view is only handling it's appearance.
__________________
My Apps on AppStore : gScale (guitar scales reference), eMaze, eMaze Lite, eTimesheet
exorcyze is offline   Reply With Quote
Old 10-22-2009, 07:03 AM   #9 (permalink)
Registered Member
 
Join Date: Jul 2009
Posts: 30
Default

I have a different point of vue, i dont think that using :

Code:
if ([myDelegate isKindOfClass:[UIViewController class]]){
  //take appropriate steps
} else if ([myDelegate isKindOfClass:[WeirdCustomObject class]]){
  //take appropriate steps
}
is the appropriate method... Delegation is made to avoid that. (What if you rename, add or remove a controller ? you will have to edit your view, which is the opposite of the separation of concern principle : your component should not need to know which controller implement it.
Imagine that the UITableView component was supposed to check which controller is calling it to know what to do : each time you create a new app you would have to edit the UITableView code, it would be absurd)

You have to declare a protocol in your view; any controller which needs to receive messages from your view will set itself as delegate of your view,
and when when you need to display a modal view, call your delegate.


In your view you have :

Code:
if(somethingHappened) {
  [delegate presentModalView];
}
Then in each different controller you will have :

in the set up :
Code:
theView.delegate = self;
and the protocol implementation :

Code:
-(void) presentModalView {
 //present the appropriate modal view according to the controller
}

Your view should never directly present a modal view controller, it's the controller job.
The view is only here to display stuff and send message when user do something.

Vincent.

Last edited by colionel; 10-22-2009 at 07:10 AM.
colionel is offline   Reply With Quote
Old 10-22-2009, 07:08 AM   #10 (permalink)
Registered Member
 
Join Date: Jul 2009
Posts: 30
Default

[sorry double post, delete this one please]

Last edited by colionel; 10-22-2009 at 07:11 AM.
colionel is offline   Reply With Quote
Old 10-22-2009, 08:49 AM   #11 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Ypsilanti, Michigan
Age: 63
Posts: 1,526
Default

Quote:
Originally Posted by exorcyze View Post
...I find it a bit annoying that UIViewController *controller isn't automatically a property on UIView inherently, and thusly I have to declare it every time. Especially considering that controllers have a UIView *view property....
That's because every view controller must have a view, but not every view must have a controller.

Robert Scott
Ypsilanti, Michigan
RLScott is offline   Reply With Quote
Old 10-22-2009, 12:41 PM   #12 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 495
Default

Quote:
Originally Posted by RLScott View Post
That's because every view controller must have a view, but not every view must have a controller.
Yup, I understand the logic and reasoning, but still wish I didn't have to type it every time, heh. =)
__________________
My Apps on AppStore : gScale (guitar scales reference), eMaze, eMaze Lite, eTimesheet
exorcyze is offline   Reply With Quote
Old 10-22-2009, 12:48 PM   #13 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Default Architecture

I am fascinated by this discussion, because I've been thinking a lot about architecture lately. (Perhaps I should start a separate post?)

The more apps I build, the more I want two levels of controller objects: "page" controllers (UIViewController subclasses) and "widget" controllers (UIView, UIImageView, or other UI element subclasses).

I now agree with colionel that the viewController should be in charge of presenting a modal view, because that is obviously on the page level. (Thanks for the code specifying the delegate protocol.) Although I don't see why subclasses of UIView couldn't have a *controller property that refers to their current view controller -- it only has one at a time, and that property should only be invoked in the context of some view controller, no?

But I'm also having lots of fun creating "widget" controllers that do a lot of work, including interacting with Core Data. For example, I'm populating a form by passing Core Data objects to my widget objects, which then save their input directly to Core Data (without informing the view controller).

Any thoughts about this architecture?

You guys are great!
jazztpt is offline   Reply With Quote
Old 10-22-2009, 01:09 PM   #14 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 495
Default

Well I'm not going to say this is the best approach, but I can tell you some of the things I typically do.

1. Controlled views have a controller property. You could either do this generically or specifically ( IE UIViewController *controller or RootViewController *controller ). There is a pro/con to both approaches. The first is more generic and will fill most circumstances for passing interaction delegation back to the controller (IE, setTarget, performSelector, etc ). If you need to access specific method calls on the controller however it will require a tiny bit more typing if you want to be proper about it and cast it.

2. UIViews that are controlled ( IE base views ) don't handle any interaction themselves - anytime something happens it isn't even seen by the view. For example if I have a MenuView that creates some buttons, then when I set them up their target for the event is self.controller. It keeps things cleaner IMO, and means I have less work to do if I refactor because I didn't like the method name I chose - because then I don't also have a sub method in the view.

3. Controls / Widgets typically don't have an associated controller. For example if you're making custom table cell or button implementation, or a game sprite actor. They're just for display and they should be able to be controlled by anything that wants to use them.

4. For advanced controls that have very specific interactions and callbacks that need to happen I like to use delegates. It's how Apple has done things, it works well and it's pretty simple after you've done it a couple times. Plus it's nice to be able to see in the header what protocols are being implemented - as Colionel pointed out very correctly, it shouldn't matter *what* is using your control, just that it conforms to the expected interfaces.

Just some thoughts off the top of my head. =)
__________________
My Apps on AppStore : gScale (guitar scales reference), eMaze, eMaze Lite, eTimesheet
exorcyze is offline   Reply With Quote
Old 10-23-2009, 05:25 AM   #15 (permalink)
Registered Member
 
Join Date: Jul 2009
Posts: 30
Default

To communicate between the view and the controller you can either use delegation, either explicitly declare a UIviewController* myController property in your view.

Delegation is a loose relation between your view and your controller, most of the time this save you a lot of problems.
Explicite declaration is a tight relation between the controller and your view. I think you should avoid this as much as possible.

In fact you dont usually need to subclass UIview. There is only 2 case where i actually subclass UIView :
-When you need to create a widget or re-implement the init method, this needs to be re-usable so you must use delegation

-When you need to re-implement the drawRect to do some custom drawing. In this case you could use an explicite declaration since this view is maybe not meant to be re-used and is very specific to your controller context.

I dont see any other use case where you need to subclass UIView (maybe they are). Anyway you can never be wrong using delegation whereas with explicite declaration you can only be right in some cases (and maybe a proper architect would simply tell you that explicite delegation is an anti-pattern)



Quote:
Originally Posted by jazztpt View Post
But I'm also having lots of fun creating "widget" controllers that do a lot of work, including interacting with Core Data. For example, I'm populating a form by passing Core Data objects to my widget objects, which then save their input directly to Core Data (without informing the view controller).
No this is definitly wrong. A widget writing in core data is a big big mistake. A view should never interact with your model !
If you want to follow the MVC pattern, this is how you would do that :

The view needs data to populate the form.
It just sends message to its delegate saying "hey i need this and that"
A controller that set itself as delegate of your views receives theses messages.
it then calls a specific class (a service) saying hey get me this data.
The service knows where to find the data (in core Data for example, or in an xml or whatever)
then the service returns the data
the controller formats the data
the view displays the data.

If you follow that pattern you only have very loose relation in your application:
- you can replace core data with a webservice your controller and views stays exactly the same, 0 lines of code.
- you can meet a designer, he gives you amazing idea about the way your apps look, you can replace all your views and your services and data will stay the same.
- you can create a new apps which uses the same widget, plug it to your new controller and services, the widget will stay unchanged, etc, etc, etc
colionel is offline   Reply With Quote
Old 10-23-2009, 09:34 AM   #16 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Default

Quote:
Originally Posted by colionel View Post
No this is definitly wrong. A widget writing in core data is a big big mistake. A view should never interact with your model !
If you want to follow the MVC pattern....
I am following the MVC pattern. I don't think my approach is so wrong, and I think I may be confusing the issue by saying that I am subclassing UIView. I'm only subclassing UIView or UIImageView because these widgets have a skin, but really it should be an NSObject that contains a UIView/UIImageView. (Each of these widgets has subviews, so I felt it was simpler to subclass UIView rather than creating one extra level of objects...I don't think that really matters. The MVC views are created with nibs.)

In my MVC architecture, I simply have an extra controller level: the widget controller. So in my architecture, sometimes the "view controller" (a controller that controls an entire screen) interacts with Core Data, and other times a "widget controller" (a controller that controls only a small functional object on the screen) interacts with Core Data.

The view level is changed by nibs and images, and is still separate from the control level. I just don't see why it is important to pass everything that interacts with a functional object on the screen through the UIViewController subclass. Some functionality affects only a small widget object (and can get info from/set info in Core Data); other functionality impacts the entire screen.

These two levels should be separate. Otherwise your UIViewController subclasses become bloated simply passing data back and forth that has nothing to do with them. They should create the objects that are on the screen, passing them any data they need, and then receive only messages that affect the screen: navigation, modal views, table updates, etc.
jazztpt is offline   Reply With Quote
Old 10-23-2009, 10:26 AM   #17 (permalink)
Registered Member
 
Join Date: Jul 2009
Posts: 30
Default

Quote:
Originally Posted by jazztpt View Post
I'm only subclassing UIView or UIImageView because these widgets have a skin, but really it should be an NSObject that contains a UIView/UIImageView.
But why not simply have a skin property in your controller ? that's the normal way to do this.. in your viewDidLoad you set your skin to your view.. No need to subclass UIView.


Quote:
Originally Posted by jazztpt View Post
So in my architecture, sometimes the "view controller" (a controller that controls an entire screen) interacts with Core Data, and other times a "widget controller" (a controller that controls only a small functional object on the screen) interacts with Core Data.
What if tomorrow you use a webservice instead of core data ? you have to rewrite everything.
The question is not do you need core data, the question is can i handle changes easily.


Quote:
Originally Posted by jazztpt View Post
I just don't see why it is important to pass everything that interacts with a functional object on the screen through the UIViewController subclass. Some functionality affects only a small widget object (and can get info from/set info in Core Data); other functionality impacts the entire screen.
Imagine that the UITextField widget was reading and writing from core data. When you want to use it you need to edit the framework. That would be a nightmare. Your widget must not decide how your system is built, it's your system which decides how to use a widget...
colionel is offline   Reply With Quote
Old 10-23-2009, 11:15 AM   #18 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 32
Default

colionel: I'm intrigued by your use of a service. I haven't seen this before, so I'm imagining how this would work. In the Apple sample code I've seen, the UIViewController subclasses access Core Data directly...I assume that each UIViewController subclass would import the service, then use it each time it wanted to read/write data.

If this is the basic paradigm, why couldn't a widget controller also access the service?

Quote:
Originally Posted by colionel View Post
But why not simply have a skin property in your controller ? that's the normal way to do this.. in your viewDidLoad you set your skin to your view.. No need to subclass UIView.
As I said, these widget controller objects should be NSObjects with a view property and subviews, mirroring the UIViewController paradigm.

Quote:
Originally Posted by colionel View Post
Imagine that the UITextField widget was reading and writing from core data. When you want to use it you need to edit the framework. That would be a nightmare. Your widget must not decide how your system is built, it's your system which decides how to use a widget...
I'm not building framework-reusable widgets, I'm building single-app reusable widgets. I have n screens, each of which is dynamically populated with any number of five types of widgets. Since the widgets function identically and are populated dynamically, I think reuse is served when they are separate objects.

Is there a reason not to have them access the service?
jazztpt is offline   Reply With Quote
Reply

Bookmarks

Tags
reuse, view, view controller

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 236
17 members and 219 guests
@sandris, ADY, dacapo, Dani77, djohnson, HemiMG, jansan, JasonR, MarkC, mer10, nibeck, prchn4christ, ryandb2, spiderguy84, timle8n1, tomtom100
Most users ever online was 1,187, 10-11-2011 at 08:09 AM.
» Stats
Members: 158,882
Threads: 89,228
Posts: 380,762
Top Poster: BrianSlick (7,129)
Welcome to our newest member, jansan
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 02:02 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0