附言:
这不是一个自以为是的问题。在 VIPER 中连接各种模块是一个合理的怀疑。这是一个理论问题,因此没有附加代码。我只需要知道我们如何在这种特定情况下连接 View-Presenter-Router 而不会破坏 VIPER
我是第一次尝试使用 VIPER。这是我对 VIPER 的基本理解。
View:应该显示 UI 控件并捕获 IBActions 并调用它的 presenter 的委托(delegate)方法来处理事件
Presenter: 将处理所有与 UI 相关的数据并准备渲染数据并将数据移交给 View。每当需要屏幕转换时,它都会调用其路由器并要求路由器执行转换
P.S: Presenter 中不会有任何 UIComponents。所以在 presenter 中没有 import UIKit 语句。
Router: 负责执行屏幕转换,通常在线框的帮助下完成(可选但最好在应用程序中有这样的类)
Interactor:包含所有业务逻辑。Presenter会在需要根据业务逻辑进行处理时调用Interactor。
实体 POJO 类(简单 Swift 对象或核心数据实体)。
问题来了:
如果我的假设是正确的,Presenter 应该是一个普通的 Swift 类,没有 UIKit 访问权限。
如果为真,假设我在我的 ViewControllerA 上按下了一个按钮,我需要将另一个 ViewControllerB 推到它上面,显然 ViewControllerA 会与 PresenterA 对话并告诉它按钮被点击,现在 PresenterA 应该与 RouterA 对话并告诉它推送 ViewControllerB。
因为 Router 可以访问 UIKit 我可以使用 Storyboard实例或从 xib 轻松创建 ViewControllerB 的新实例,但为了推送该实例我需要ViewControllerA 的实例。
但是 PresenterA 不能持有对 ViewControllerA 的引用,或者可以在函数中作为参数传递给 PresenterA 因为 UIViewController 属于 UIKit,Presenter 不应该有 UI 语句。
我能想到的可能解决方案:
解决方案一:
在创建 Router 实例时,将相应的 ViewController 实例作为其初始化(依赖注入(inject)阶段)的一部分传递,这样 Router 将始终引用它所属的 ViewController
解决方案 2:
让 Router 声明其协议(protocol)并在 ViewController 中实现它,并且每当需要引用 ViewController 时使用 Router 的委托(delegate)。但这与路由器不应该与 View 通信的 VIPER 规则相矛盾。
我的思路是否清晰?我的假设是否正确?如果是,处理这个问题的正确方法是什么,请提出建议
最佳答案
关于 iOS 应用程序的 VIPER 的任何建议或意见都是值得商榷的,因为 VIPER 并不严格适合 iOS 的 UIKit 设计。但是,如果我可以把我的两分钱放在讨论中:
首先,我认为 UIViewController 非常适合 VIPER 模式中的 Presenter 角色,因此 ViewControllerA 不需要与自身和 Router 之间的任何类对话 - 直接与 Router 通信。
其次,应该只有一个 Router 对象 - 因为应用程序只有一个 View /导航堆栈。出于这个原因,为 Router 实现 Singleton 模式是理想的,所以 ViewControllerA(或 Presenter,如果你我宁愿让您的 ViewControllers 在该模式中执行 View 的角色)不需要保留对 Router 的引用。
第三,您不需要将对 ViewControllerA 的引用传递给您的 Router - Router 应该已经有对它的引用,因为 Router 应该首先显示它。类似的东西:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
{
// ...
window?.rootViewController = Router.shared.rootViewController
// ...
}
class Router
{
static let shared = Router()
let rootViewController = ViewControllerA() // or UINavigationController, or UITabBarController etc.
}
Router 应该跟踪导航堆栈并保持对当前呈现的 ViewController
但这就是我的看法。
关于ios - 如何在 VIPER 设计模式中将 ViewController Reference 传递给 Router?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51554171/
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数