在视图控制器之间进行通信的最佳方式是什么? [英] What's the best way to communicate between view controllers?

查看:182
本文介绍了在视图控制器之间进行通信的最佳方式是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于C,可可和iPhone开发人员来说,一直以来都是新兴的,我非常希望充分利用语言和框架。我使用的资源之一是斯坦福大学的CS193P课程笔记,他们已经在网上。它包括演讲笔记,作业和示例代码,并且由于Apple开发人员的课程,我绝对认为它是从马的嘴。

One of the resources I'm using is Stanford's CS193P class notes that they have left on the web. It includes lecture notes, assignments and sample code, and since the course was given by Apple dev's, I definitely consider it to be "from the horse's mouth".

类网站:

http://www.stanford.edu /class/cs193p/cgi-bin/index.php

讲座08与构建基于UINavigationController的应用程序相关,该应用程序将多个UIViewController推送到UINavigationController堆栈。这就是UINavigationController的工作原理。这是合乎逻辑的但是,关于UIViewControllers之间沟通的幻灯片中有一些严厉的警告。

Lecture 08 is related to an assignment to build a UINavigationController based app that has multiple UIViewControllers pushed onto the UINavigationController stack. That's how the UINavigationController works. That's logical. However, there are some stern warnings in the slide about communicating between your UIViewControllers.

我将从这个严重的幻灯片中引用:

http://cs193p.stanford.edu/downloads/08-NavigationTabBarControllers.pdf

I'm going to quote from this serious of slides:
http://cs193p.stanford.edu/downloads/08-NavigationTabBarControllers.pdf

第16/51页:


如何共享数据




  • 全局变量或单例


    • 这包括您的应用程序委托

How Not To Share Data

  • Global Variables or singletons
    • This includes your application delegate

  • 更难调试&测试

我下来了不要盲目地抛出所有用于将viewcontroller通信到您的应用程序委托中的方法,并在应用程序委托方法中引用viewcontroller实例。

Ok. I'm down with that. Don't blindly toss all your methods that will be used for communicating between the viewcontroller into your app delegate and reference the viewcontroller instances in the app delegate methods. Fair 'nuff.

进一步,我们收到这张幻灯片告诉我们,我们应该如何做。

A bit further on, we get this slide telling us what we should do.

第18/51页:


数据流的最佳做法




  • 确定需要传达的内容

  • 为您的视图定义输入参数控制器

  • 要进行层次结构的备份,使用松散耦合


    • 定义一个通用观察者界面(如委派)

Best Practices for Data Flow

  • Figure out exactly what needs to be communicated
  • Define input parameters for your view controller
  • For communicating back up the hierarchy, use loose coupling
    • Define a generic interface for observers (like delegation)

此幻灯片之后是看起来是一个占位符幻灯片,讲师然后显然演示了使用UIImagePickerController的示例的最佳实践。我希望视频可用! :(

This slide is then followed by what appears to be a place holder slide where the lecturer then apparently demonstrates the best practices using an example with the UIImagePickerController. I wish the videos were available! :(

好吧,我恐怕我的objc-fu不那么强壮,我也在上面的最后一行感到困惑引用我已经做了我公平的谷歌搜索这个,我发现似乎是一个体面的文章谈论观察/通知技巧的各种方法:

http://cocoawithlove.com/2008/06/five-approaches-to-listening-observing.html

Ok, so... I'm afraid my objc-fu is not so strong. I'm also a bit confused by the final line in the above quote. I've been doing my fair share of googling about this and I found what appears to be a decent article talking about the various methods of Observing/Notification techniques:
http://cocoawithlove.com/2008/06/five-approaches-to-listening-observing.html

方法#5甚至表示代理方法!除了....对象一次只能设置一个代理,所以当我有多个viewcontroller通信,我该怎么办?

Method #5 even indicates delegates as an method! Except.... objects can only set one delegate at a time. So when I have multiple viewcontroller communication, what am I to do?

好的,这是设置帮派,我知道我可以很容易地通过引用的多个viewcontroller实例在应用程序委托中做我的通信方法在我的appdelegate,但我想做这样的事情正确的方式。

Ok, that's the set up gang. I know I can easily do my communication methods in the app delegate by reference's the multiple viewcontroller instances in my appdelegate but I want to do this sort of thing the right way.

请帮助我做正确事情通过回答以下问题:

Please help me "do the right thing" by answering the following questions:


  1. 当我试图在UINavigationController堆栈上推新的viewcontroller时,强>应该这样做。 我的代码中的哪个类/文件是正确的地方?

  2. 当我想影响我的一个UIViewControllers中的某些数据(iVar的值)当我在一个不同的 UIViewController中时,这样做的正确方式是什么?

  3. 给我们一次只能有一个委托一个对象,当讲师说em定义观察者的一般界面(如委派)时,实现看起来会如何。如果可能,伪代码示例将非常有用。

  1. When I am trying to push a new viewcontroller on the UINavigationController stack, who should be doing this push. Which class/file in my code is the correct place?
  2. When I want to affect some piece of data (value of an iVar) in one of my UIViewControllers when I am in a different UIViewController, what is the "right" way to do this?
  3. Give that we can only have one delegate set at a time in an object, what would the implementation look like for when the lecturer says "Define a generic interface for observers (like delegation)". A pseudocode example would be awfully helpful here if possible.


推荐答案

这些都是好问题,很高兴看到您正在做这项研究,并且似乎关心学习如何做正确,而不是仅仅将其一起攻击。

These are good questions, and its great to see that you're doing this research and seem concerned with learning how to "do it right" instead of just hacking it together.

>首先 ,我同意以前的答案,重点是在适当的时候(根据MVC设计模式)将数据放在模型对象中的重要性。通常你想避免将状态信息放在控制器中,除非是严格的演示数据。

First, I agree with the previous answers which focus on the importance of putting data in model objects when appropriate (per the MVC design pattern). Usually you want to avoid putting state information inside a controller, unless it's strictly "presentation" data.

第二个 ,参见斯坦福演示文稿第10页,了解如何以编程方式将控制器推送到导航控制器上。有关如何使用Interface Builder视觉执行此操作的示例,请查看本教程

第三个​​ ,也许最重要的是注意如果您在依赖注入设计模式的上下文中思考,那么在斯坦福大学演讲中提到的最佳做法会更容易理解。简而言之,这意味着您的控制器不应该查找需要执行其作业的对象(例如,引用全局变量)。相反,您应该始终将这些依赖项注入到控制器中(即,通过方法传递需要的对象)。

Third, and perhaps most importantly, note that the "best practices" mentioned in the Stanford presentation are much easier to understand if you think about them in the context of the "dependency injection" design pattern. In a nutshell, this means that your controller shouldn't "look up" the objects it needs to do its job (e.g., reference a global variable). Instead, you should always "inject" those dependencies into the controller (i.e., pass in the objects it needs via methods).

如果遵循依赖注入模式,则控制器将模块化并可重复使用。如果您考虑到斯坦福大学的演讲者来自哪里(也就是说,由于苹果员工的工作是建立可以轻松重用的课程),可重用性和模块化是高度重视的。他们提到的用于共享数据的所有最佳做法都是依赖注入的一部分。

If you follow the dependency injection pattern, your controller will be modular and reusable. And if you think about where the Stanford presenters are coming from (i.e., as Apple employees their job is to build classes that can easily be reused), reusability and modularity are high priorities. All of the best practices they mention for sharing data are part of dependency injection.

这是我的回应的要点。我将包括一个使用依赖注入模式的例子,如果它是有帮助的,

That's the gist of my response. I'll include an example of using the dependency injection pattern with a controller below in case it's helpful.

使用View Controller使用依赖注入示例

Example of Using Dependency Injection with a View Controller

假设您正在构建一个屏幕,其中列出了几本书。用户可以选择他/她想要购买的书籍,然后点击结帐按钮转到结帐屏幕。

Let's say you're building a screen in which several books are listed. The user can pick books he/she wants to buy, and then tap a "checkout" button to go to the checkout screen.

要构建它,您可以创建一个控制和显示GUI /视图对象的BookPickerViewController类。哪里可以获取所有的书籍资料?假设这取决于一个BookWarehouse对象。所以现在你的控制器基本上是在模型对象(BookWarehouse)和GUI /视图对象之间经纪。换句话说,BookPickerViewController DEPENDS在BookWarehouse对象上。

To build this, you might create a BookPickerViewController class that controlls and displays the GUI/view objects. Where will it get all the book data? Let's say it depends on a BookWarehouse object for that. So now your controller is basically brokering data between a model object (BookWarehouse) and the GUI/view objects. In other words, BookPickerViewController DEPENDS on the BookWarehouse object.

不要这样做:

@implementation BookPickerViewController

-(void) doSomething {
   // I need to do something with the BookWarehouse so I'm going to look it up
   // using the BookWarehouse class method (comparable to a global variable)
   BookWarehouse *warehouse = [BookWarehouse getSingleton];
   ...
}

相反,依赖关系应该像这样注入:

Instead, the dependencies should be injected like this:

@implementation BookPickerViewController

-(void) initWithWarehouse: (BookWarehouse*)warehouse {
   // myBookWarehouse is an instance variable
   myBookWarehouse = warehouse;
   [myBookWarehouse retain];
}

-(void) doSomething {
   // I need to do something with the BookWarehouse object which was 
   // injected for me
   [myBookWarehouse listBooks];
   ...
}

当苹果公司正在谈论使用委托模式交换备份层次结构,他们仍在谈论依赖注入。在这个例子中,一旦用户选择了他/她的书籍并准备退房,BookPickerViewController应该怎么做?那真的不是它的工作。它应该将该工作转移给其他对象,这意味着它对另一个对象的依赖。所以我们可以修改我们的BookPickerViewController init方法如下:

When the Apple guys are talking about using the delegation pattern to "communicate back up the hierarchy," they're still talking about dependency injection. In this example, what should the BookPickerViewController do once the user has picked his/her books and is ready to check out? Well, that's not really its job. It should DELEGATE that work to some other object, which means that it DEPENDS on another object. So we might modify our BookPickerViewController init method as follows:

@implementation BookPickerViewController

-(void) initWithWarehouse:    (BookWarehouse*)warehouse 
        andCheckoutController:(CheckoutController*)checkoutController 
{
   myBookWarehouse = warehouse;
   myCheckoutController = checkoutController;
}

-(void) handleCheckout {
   // We've collected the user's book picks in a "bookPicks" variable
   [myCheckoutController handleCheckout: bookPicks];
   ...
}

所有这一切的最终结果是你可以给我你的BookPickerViewController类(和相关的GUI /视图对象),我可以轻松地在我自己的应用程序中使用它,假设BookWarehouse和CheckoutController是我可以实现的通用接口(即协议):

The net result of all this is that you can give me your BookPickerViewController class (and related GUI/view objects) and I can easily use it in my own application, assuming BookWarehouse and CheckoutController are generic interfaces (i.e., protocols) that I can implement:

@interface MyBookWarehouse : NSObject <BookWarehouse> { ... } @end
@implementation MyBookWarehouse { ... } @end

@interface MyCheckoutController : NSObject <CheckoutController> { ... } @end
@implementation MyCheckoutController { ... } @end

...

-(void) applicationDidFinishLoading {
   MyBookWarehouse *myWarehouse = [[MyBookWarehouse alloc]init];
   MyCheckoutController *myCheckout = [[MyCheckoutController alloc]init];

   BookPickerViewController *bookPicker = [[BookPickerViewController alloc] 
                                         initWithWarehouse:myWarehouse 
                                         andCheckoutController:myCheckout];
   ...
   [window addSubview:[bookPicker view]];
   [window makeKeyAndVisible];
}

最后,不仅您的BookPickerController可重用,还易于测试。

Finally, not only is your BookPickerController reusable but also easier to test.

-(void) testBookPickerController {
   MockBookWarehouse *myWarehouse = [[MockBookWarehouse alloc]init];
   MockCheckoutController *myCheckout = [[MockCheckoutController alloc]init];

   BookPickerViewController *bookPicker = [[BookPickerViewController alloc] initWithWarehouse:myWarehouse andCheckoutController:myCheckout];
   ...
   [bookPicker handleCheckout];

   // Do stuff to verify that BookPickerViewController correctly called
   // MockCheckoutController's handleCheckout: method and passed it a valid
   // list of books
   ...
}

这篇关于在视图控制器之间进行通信的最佳方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆