草庐IT

objective-c - 在 View Controller 之间传递应用上下文

coder 2024-01-17 原文

与使用全局状态相比,我看到了在 View Controller 之间传递依赖关系(注入(inject))的好处。不过,我很好奇人们是如何在实践中实现这一点的。

在最简单的情况下,很容易在两个 View Controller 之间传递单个模型:

MyViewController *vc = [[MyViewController alloc] init];
vc.model = model;
[self.navigationController pushViewController:vc animated:YES];

然而,我发现扩展这种方法有两个问题:

1) 您可能有一些所有 View Controller 都需要的服务(位置管理器、对象存储等)。因此,您最终会得到一个必须记住为每个 View Controller 设置的依赖项列表:

MyViewController *vc = [[MyViewController alloc] init];
vc.model = model;
vc.locationManager = locationManager;
vc.objectStore = objectStore;
...
[self.navigationController pushViewController:vc animated:YES];

2) 第二个问题与第一个问题相关:您实际上并没有强制在推送 View Controller 之前设置这些依赖项。我想你可以编写一个需要所有依赖项的 init 方法,但你仍然不能强制执行它。它也将是冗长的,如果你想稍后添加依赖项,那将是一个巨大的痛苦。

处理这些问题的方法是什么?似乎很多 Obj-C 人员都没有使用依赖注入(inject)框架。我能想到的一种方法是创建一个包含所有共享依赖项的 AppContext 类,然后将其传递给所有 View Controller 。

此外,通常您使用接口(interface)而不是实现来声明依赖项(至少在 Java 中),因此您可以模拟它们以进行单元测试。我没有看到很多 Obj-C 人员以这种方式使用协议(protocol)。然后如何为单元测试模拟依赖项?

最佳答案

依赖注入(inject)的关键是所有硬依赖都应该在构造函数中指定!

因此,您的构造函数应如下所示:

- (id)initWithModel:(Model *)model locationManager:(LocationManager *)locationManager objectStore:(ObjectStore *)objectStore;

任何不是可选的并且提供类本身不应该负责构造的设施的东西都应该在构造函数中指定。这也是测试中的一个巨大帮助,因为可以为对象本身提供其依赖项的模拟版本,以隔离网络套接字、存储后端等...

如果这看起来很麻烦并且您觉得构造函数看起来太大或太丑,这不是因为这些应该是属性或隐式依赖!这可能意味着该类试图做太多事情,或者它的依赖项可以分解为复合对象。

我在一个非常大的(100,000 行)生产 iPhone 应用程序上工作,并且非常坚持测试驱动开发。实际上,我实现依赖注入(inject)的方法是通过协议(protocol)。您的观察完全正确,您在 Internet 上看到的示例代码很少是用这种方式编写的,但它是 100% 正确和适当的。

我一直使用的一个非常有用的模式是有两个构造函数,一个公开了所有依赖项,一个具有较少的构造函数参数和隐式默认值(用于生产)。

例如:

// Fully exposed constructor, for easy unit testing.
- (id)initWithHost:(NSString *)host storageProvider:(id<StorageProvider>)storageProvider socketFactory:(id<SocketFactory>)socketFactory;

// Constructor that calls the former, with fully-functional defaults passed into former constructor implicitly.
- (id)initWithHost;

这种模式与良好的模拟框架(OCMockito 或 OCMock 都很好)相结合,将使您在设计干净、诚实和高度可测试的代码方面走得更远。 :)

关于objective-c - 在 View Controller 之间传递应用上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11771113/

有关objective-c - 在 View Controller 之间传递应用上下文的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  5. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  6. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  7. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  10. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

随机推荐