I have a view
with alot of logic code that would be better of in a viewmodel
. The problem is that the code has references to the view
which means that the viewmodel
would need an object from the view
to work properly. If I understand the concept of a viewmodel
correctly, having a two-way dependency defeats the whole purpose of a viewmodel
As you can see from the code below it contains the line addChild(x)
as well as .removeFromParent
. So if moved to a viewmodel
the code would have to be something like: mainView.addChild(x)
. It works sure enough, but my question is if it's appropriate. If not, should I just keep the code in the view, even though it takes up alot of space and has alot of logic in it?
These functions are used in the native touchDown()
function:
func characterIsSelected(i: Int, j: Int) {
//Check Accessibility of Tile
if !gameBoardArray[i][j].isAccessibilityElement {
hasBeenClickedOnce = true
characterIsSelected = true
characterVM.getGameBoardPosition().fillColor = SKColor.brown
print("NOT ACCESSIBLE")
return
}else {
print("Moving")
viewModel.placeCharacter(row: i, col: j)
buttonIsAvailable = false
//SEE HERE
guiButton.removeFromParent()
enemyProximityCheck(i: i, j: j)
}
}
func enemyProximityCheck(i: Int, j: Int){
print("ENEMY PROXIMITY")
//SCAN VICINITY OF CHARACTER. IF ENEMY IS ON TILE, GOTO COMBAT
for ii in -1...1 {
for jj in -1...1 {
//gameBoardArray[i + (ii)][j + (jj)].fillColor = SKColor.blue
if(i + (ii) < 0 || j + (jj) < 0 ) {
print("LOW")
}
else if(i + (ii) > gameBoardArray.count - 1 || j + (jj) > gameBoardArray.count - 1) {
print("HIGH")
}
else {
if (gameBoardArray[i + (ii)][j + (jj)].contains(enemyVM.getCurrentEnemyPosition() ) ) {
print("AAARGH AN ENEMY!")
//SEE HERE
addChild(guiButton)
buttonIsAvailable = true
//enemyHasBeenSpotted = true
}
}
}
}//End for
}
Generally if you’re using a “view model”, the view model would not generally be manipulating the view directly. It would simply communicate the “encountered enemy” (or whatever) event to the “view” (which many of us would consider to be both the UIView
hierarchy and the view controller, too), which would then be responsible for manipulating the view(s) accordingly.
Unfortunately, it’s hard to say precisely how the view model would do this in your case, on the basis of what you’ve outlined. Some use the term “view model” loosely, so there are a couple of possible interpretations:
One approach is to have the view observe (through some “binding” mechanism) some property in the view model, and when the view model updates that state, the view would then add/configure the appropriate views/subviews accordingly. (This is binding/observing is arguably an essential aspect of any “view model” based approach.)
Other approaches include protocol-delegate or closure patterns for the view model to communicate that UI updates to the view. (This is arguably more of a MVP sort of approach, though I’ve seen teams use the term “view model” in this context, too.)
But the consistent pattern is that the view model should generally not be reaching in and manipulating the view hierarchy itself. It should simply communicate (one way or the other) the state change, and the “view” would take it over from there.
FYI, I think Medium’s iOS Architecture Patterns is illuminating when talking about these various patterns in the context of iOS apps.