菜鸟教程小白 发表于 2022-12-13 15:30:15

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


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

<p>在最简单的情况下,很容易在两个 ViewController 之间传递一个模型:</p>

<pre><code>MyViewController *vc = [ init];
vc.model = model;
;
</code></pre>

<p>但是,我发现扩展这种方法存在两个问题:</p>

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

<pre><code>MyViewController *vc = [ init];
vc.model = model;
vc.locationManager = locationManager;
vc.objectStore = objectStore;
...
;
</code></pre>

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

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

<p>此外,通常您使用接口(interface)而不是实现来声明依赖项(至少在 Java 中),因此您可以模拟它们以进行单元测试。我没有看到很多 Obj-C 人以这种方式使用协议(protocol)。然后如何模拟单元测试的依赖关系?</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>依赖注入(inject)的关键是<em>所有的硬依赖都应该在构造函数中指定!</em></p>

<p>因此,您的构造函数应该如下所示:</p>

<pre><code>- (id)initWithModel:(Model *)model locationManager:(LocationManager *)locationManager objectStore:(ObjectStore *)objectStore;
</code></pre>

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

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

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

<p>我一直使用的一个非常有用的模式是有两个构造函数,一个暴露所有依赖项,一个具有更少的构造函数参数和隐式默认值(用于生产)。</p>

<p>例如:</p>

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

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

<p>这种模式与良好的模拟框架(OCMockito 或 OCMock 都很好)相结合,将使您在设计干净、诚实和高度可测试的代码方面走得更远。 :)</p></p>
                                   
                                                <p style="font-size: 20px;">关于objective-c - 在 ViewController 之间传递应用程序上下文,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/11771113/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/11771113/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: objective-c - 在 View Controller 之间传递应用程序上下文