在我的代码中,我一直在使用苹果公司在他们的演示中展示的MVC模式。但是,我试图通过遵循MVVM模式来减少膨胀的UIViewController
来回避编写更清晰,更健壮的代码:
我对它的理解是Controller
和View
对Model
一无所知,但与中间人ViewModel
进行通信,中间人Model
存储有关Controller
并将其传递给View
,后者又会更新Model
。
我已将代码重新构建为ViewModel
和struct PersonModel
{
public var name: String
public var position: String
public var imageLink: String
public var listOrder: Int
init()
{
self.name = "Unknown"
self.position = "Unknown"
self.imageLink = "url link"
self.listOrder = 0
}
init(name: String, position: String, imageLink: String, listOrder: Int)
{
self.name = name
self.position = position
self.imageLink = imageLink
self.listOrder = listOrder
}
}
class PersonViewModel
{
fileprivate var personModel: PersonModel
public var name: String {
return personModel.name
}
public var position: String {
return personModel.position
}
public var imageLink: String {
return personModel.imageLink
}
public var listOrder: Int {
return personModel.listOrder
}
init(personModel: PersonModel)
{
self.personModel = personModel
}
}
,如下所示:
UIViewController
这看起来很简单。
我目前遇到的问题是清除当前位于我的PersonModel
中的其他代码,这些代码会执行一些代码以检索表示{{1}的 JSON 对象},并验证其数据内容。
var personInfo = [PersonModel]()
func retrieveFromDatabase()
{
let json = JSON()
json.getJSONData(link: "database link") { (json) in
if json.isEmpty == false
{
self.storeJSONData(json: json)
}
}
}
func storeJSONData(json: [String : Any])
{
for key in json.keys.sorted()
{
// Store each person information
guard let info = json[key] as? [String: Any] else {
return
}
let name = retrieveProperty(json: info,
property: "Name Field")
let position = retrieveProperty(json: info,
property: "Position Field")
let listOrder = retrieveProperty(json: info,
property: "List Order Field")
let imageLink = retrieveProperty(json: info,
property: "Image Link Field")
let person = checkData(name: name,
listOrder: Int(listOrder)!,
position: position,
imageLink: imageLink)
personInfo.append(person)
}
}
func retrieveProperty(json: [String : Any], property: String) -> String
{
guard let attribute = json[property] as? String else {
return ""
}
return attribute
}
func checkData(name: String, listOrder: Int, position: String, imageLink: String) -> PersonModel
{
var person = PersonModel()
person.listOrder = listOrder
if name.isEmpty == false
{
person.name = name
}
if position.isEmpty == false
{
person.position = position
}
if imageLink.isEmpty == false
{
person.imageLink = imageLink
}
return person
}
func getPersonInfo(sectionRow: Int) -> PersonModel
{
let person = PersonModel(name: personInfo[sectionRow].name,
position: personInfo[sectionRow].position,
imageLink: personInfo[sectionRow].imageLink,
listOrder: personInfo[sectionRow].listOrder)
return person
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell",
for: indexPath) as! CustomCell
let personModel = getPersonInfo(sectionRow: indexPath.row)
guard let url = URL(string: personModel.imageLink) else {
return UICollectionViewCell()
}
let imageResouce = ImageResource(downloadURL: url,
cacheKey: personModel.imageLink)
cell.staffImageView.kf.setImage(with: imageResouce,
placeholder: #imageLiteral(resourceName: "default_profile"),
options: [.transition( .fade(0.3) ),
.fromMemoryCacheOrRefresh]
)
cell.nameLabel.text = personModel.name
cell.positionLabel.text = personModel.position
return cell
}
PersonViewModel
,而不是当前驻留在Controller
?Controller
课程中,我需要在函数调用PersonModelView
存储所有JSON数据后访问包含PersonModel
数据的storeJSONData
数组。如何正确构建我的代码,以便我的Controller
可以在仍然遵守MVVM模式的同时访问它?请原谅我,因为我是新手学习这种模式,并希望得到一些指导。
谢谢!
答案 0 :(得分:1)
要遵循MVVM模式,上述 JSON 代码是否会迁移到
PersonViewModel
而不是当前驻留在Controller中?
我认为,MVVM模式全部都是关于"前端"移动应用的一部分。由于viewModel并不真正了解任何UIKit
事物,因此它也不应该知道任何类型的"如何将JSON转换为模型","如何处理缓存"或者"创建alamofire请求"。这部分是"后端",这就是为什么应该在这里引入不同的特定类(例如,你可以称它们为service
)。
在我的
Controller
课程中,我需要在函数调用PersonModelView
存储所有JSON数据后访问包含PersonModel
数据的storeJSONData
数组。如何正确构建我的代码,以便我的Controller
可以在仍然遵守MVVM模式的同时访问它?
注意:也许您不应该创建包含PersonModelView
"的PersonModel
数组,但只创建一个viewModel包含模型数组?
根据最高评论,我这样处理:
Controller
viewDidLaod
方法中创建viewModel
; viewModel
中创建任何configure
initialize
个service
func,可以从您特定的Controller
中找回模型; closures
所有存储的数据。为此,您可以使用red
或更具体的工具,例如PromiseKit(google promises),RxSwift等。这是我个人试图遵循的几件事。
有点深入解释。
图例:green
行向下移动以获取数据; configure
个数据将数据带到顶部(UI)。
所以,正如我所提到的,getPersons
或PersonService
方法调用getPersons
PersonModel
方法来检索ViewModel
(这很重要! JSON,字符串数组或任何其他简单类型 - 我们需要返回最终模型或错误(nil))。怎么回事? lazy var personService: PersonServiceProtocol = {
let personParser: PersonParserProtocol = PersonParser()
let personValidator: PersonValidationProtocol = PersonValidator()
return PersonService(parser: parser, validator: validator)
}()
有财产
parser
管理所有"后端"适合我们的事情。此外,还有一件棘手的事情:我们在validator
中设置了init
和PersonDB
,但PersonService
已经存储在Person
中。为什么?发生这种情况,因为将来您可能会有PersonService
应该检索到的parser
种不同类型的validator
。对于此类工作,您需要为不同类型的Person
手动设置DB
和Person
,但您真的不需要为每种类型的PersonDB
创建PersonService
JSON
。
当parser
成功检索数据(JSON)并将其返回validation
时(步骤4),您需要在closures
personDb.getPersons { result in
if case let .success(json) = result, self.validator.validate(json) {
let models = self.parser.parse(json)
completion(.success(models))
} else {
// error`enter code here`
}
}
和{{1}下拨打电话} funcs。在这里返回models
非常常见(或Promise,Observable,如果你使用PromiseKit或RxSwift,因为在这种情况下你可以用链式模式编写代码),即
viewModel
现在您有最终viewModel
,您可以将其传回personService.getPerson()
或应用任何修改(例如,按部分拆分),然后返回PersonDB
(步骤5)。
有时它在这里看起来有点过度编码,因为你基本上可以跳过viewModel
func并使用personService.getPerson()
中的viewModel
,解析器和验证器手动工作(即你使用Pod
}只是为了调用另一个函数),但我认为迟早你会以大量视图模型结束,这也会打破你 public boolean checkNetworkConnection()
{
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
boolean isConnected = false;
if (networkInfo != null && (isConnected = networkInfo.isConnected())) {
// show "Connected" & type of network "WIFI or MOBILE"
tvIsConnected.setText("Connected "+networkInfo.getTypeName());
// change background color to red
tvIsConnected.setBackgroundColor(0xFF7CCC26);
} else {
// show "Not Connected"
tvIsConnected.setText("Not Connected");
// change background color to green
tvIsConnected.setBackgroundColor(0xFFFF0000);
}
return isConnected;
}
的单一责任。
这是非常简单的架构。它可以工作,但你应该仔细考虑它的所有部分:也许你可以委托给.spec.revisionHistoryLimit
左右,也许某些部分(因为工作量很小)可以合并在一起。祝你好运。
答案 1 :(得分:0)
要遵循MVVM模式,上述JSON代码是否会迁移到PersonViewModel而不是当前驻留在Controller中?
我在使用MVVM时发现,将执行数据查询/操作的逻辑移动到DAO(数据访问对象)要容易得多,然后相关的ViewModel调用该对象来获取数据。这抽象出逻辑,以便其他ViewModel可以重用它。
注意:不要让DAO成为单身人士,而不是良好的做法。
在我的Controller类中,我需要访问PersonModelView数组 在所有JSON数据之后包含我的PersonModel数据 存储在函数调用storeJSONData中。我该怎么办呢 构造我的代码,以便我的控制器可以在仍然访问它时 坚持MVVM模式?
在我看来,最好对代表这样做,让ViewController成为ViewModel的委托,并将数据(在本例中为数组)从ViewModel传递给ViewController,例如。
struct PersonModel {
// Model properties here
}
class PersonViewModel {
weak var delegate: PersonViewModelDelegate?
public func getPersons() -> [PersonViewModel] {
// perform logic to get person array then return it to the delegate
let persons = [PersonViewModel]
delegate?.didGetPersons(persons: persons)
}
}
protocol PersonViewModelDelegate {
func didGetPersons(persons:[PersonViewModel])
}
class YourViewController:UIViewController {
weak var personViewModel: PersonViewModel = PersonViewModel() {
personViewModel.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
}
// your viewcontroller code goes here
}
extension YourViewController: PersonViewModelDelegate {
func didGetPersons(persons: [PersonViewModel]) {
// use persons array here
}
}