mixing value semantics and reference semantics with protocol oriented design

Hello all,


Basically I am developing a SAT prep application where there is Task by Task solutions for Questions that users can follow. Some of the Tasks are interactive where user can tap on the screen, and some of them are just read only. I am trying to follow protocol oriented programming approach and here's how I structured it:


protocol Task {
    var canInteract: Bool { get }
    var highlightText: String { get }
    var qwzrdText: String { get }


}
extension Task where Self: Interactable {
    var canInteract: Bool { return true }
}

protocol Interactable {
    var tapPoint: CGPoint { get }
}

struct SimpleTask: Task {
    let canInteract = false
    let highlightText: String
    var qwzrdText: String { return "Simple Task" }

}

struct InteractiveTask: Task, Interactable {
    let highlightText: String
    var qwzrdText: String { return "Interactive Task" }
    var tapPoint: CGPoint { return CGPointMake(100, 200) }

}

struct Solution {
    var tasks:[Task]

    mutating func addTask(newTask: Task) {
        tasks.append(newTask)
    }

}

var solution = Solution(tasks: [])

let interactiveTask = InteractiveTask(highlightText: "InteractiveTask")
solution.addTask(interactiveTask)
let simpleTask = SimpleTask(highlightText: "SimpleTask")
solution.addTask(simpleTask)


 


So I let's assume I'd like to to use above solution array as my datasource in my viewcontroller. What I am looking for is a declarative way to update the label that I bind to the above datasource on change. I know property observer is what I am looking for. What I don't know, should I have a generic variable in the viewcontroller and assign the current Task and update that? If this is the case, how am I going to address the heteragonious types that I have?


//UIViewController
var label = UILabel(frame: CGRectMake(0, 0, 200, 200))
var task = SimpleTask(highlightText: "Test") { //addresses SimpleTask but not InteractiveTask?
didSet {
        label.text = simpleTask.highlightText
    }
}
func nextTapped() {
     solution[whatever] = task
}


Thank you.

As usual, when a question contains a slab of code, it's hard to be sure you're addressing the right issue, but…


1. AFAICT there's no value in using 'didSet' on a view controller property, because nothing is going to to set it in the first place. If anything, it'd have to be (a) the data model itself, but you don't want it to know about the view controller, or (b) the view controller itself, when something relevant happens in the UI, but then you don't need the 'didSet' at all.


2. With value semantics, assigning a task to the "task" property will give it a copy of the task. That means the property won't track the actual value of the task, only the stale value it had at the time of the copy.


The problem is that value semantics are often not appropriate when the value represented is a singular, real-world state. Your Solution class is roughly the analog of (say) an exam booklet in which answers are progressively written, so it and its components seem to fall under the principle that such states are most easily handled with reference semantics. There is One True state, and you never want to copy any of it — unless you're exploring a hypothetical trial of a different set of answers, right?


Incidentally, you don't really need an "canInteract" property at all, since you can say "is Interactable" — unless an Interactable is allowed to return 'false' for that property, which makes my head hurt to contemplate.


(Edited for typos)

[CODE]var task = SimpleTask(highlightText: "Test") [\CODE] This creates a variable task; that is of type SimpleTask [CODE]var task: Task = SimpleTask(highlightText: "Test") [\CODE] Should handle the heterogeneous case.

Incidentally, you don't really need an "canInteract" property at all, since you can say "is Interactable"


Whoa, you're right! Didn't it used to be the case that non-ObjC protocols were not dynamically checkable? In any event, it seems to work now even if you only know the struct as a Task. Very helpful!


protocol Task {}
protocol Interactable {}

struct Compliant: Task, Interactable {}
struct Noncompliant: Task {}

let foo: Task = Compliant()
foo is Interactable // true

let bar: Task = Noncompliant()
bar is Interactable // false

It sounds like you might be writing for OS X, which I'm less familiar with (bindings in particular). But generally speaking, this is a good situation in which to consider using NSNotifications. Just rig some key points in the back end to generate nonspecific "the world of Tasks has changed" notifications. The view controller can completely redisplay whenever those notifications go by.


There are multiple advantages to doing it this way. You don't have to track and account for every possible change; you just write one master method that shows the current state accurately. Notifications can be coalesced, so batches of back-end changes can happen and still only cause one redraw. The model and UI remain decoupled; there's no harm in generating the notifications even if no UI is listening. And it automatically generalizes to multiple views into the data, which may become particularly important in iOS 9.


I agree with Quincey, though -- at the very least, Solution should be a reference type.

Hi Quincey,


First off thanks so much for taking time to respond.


I am sorry I made an error in the last bit of the code in my previous post: My intention was when the task was set (copied) in the nextTapped method, it automatically sets the label's text property through didSet:


//UIViewController
var label = UILabel(frame: CGRectMake(0, 0, 200, 200))
var task = SimpleTask(highlightText: "Test") { //addresses SimpleTask but not InteractiveTask?
didSet {
        label.text = task.highlightText
    }
}


func nextBtnTapped {
     var newTask = simpleTask(highlighText:"anotherTask")
     solution.add(simpleTask(highlighText:"anotherTask"))
     task = newTask //copy assign, should trigger property aobserver?

}


Your One True state explanation makes a lot sense. Each task is singular leading to one solution. The reason I persisted on value types is I would like to have a undo functionality in this application. So I thought about using Solution as a collection type where I can add Tasks to it up to the point as user goes. Then if user wants to go back, model can remove the task from the solution since it has all the copies.


Incidentally, you don't really need an "canInteract" property at all, since you can say "is Interactable"


Thanks for the tip! I wasn't aware that.

>> Then if user wants to go back, model can remove the task from the solution since it has all the copies.


Ironically, in an important sense, it's a reference type that "has all the copies", because there aren't any copies, conceptually. Value types tend to produce a lot of copies.


In your corrected code, why do you need a 'didSet'? You could have written the line 'label.text = task.highlightText' in 'nextBtnTapped', couldn't you?


Have you done much reading of the MVC (model-view-controller) design pattern? If not, I suggest you take a look, starting here:


https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html#//apple_ref/doc/uid/TP40008195-CH32-SW1


In that pattern, you can KVO (key-vlaue observation) in your view controller to register to observe properties in the Solution. That way, the view controller gets informed when something it's interested in changes, no matter the source of the change. Alternatively, you can use notifications as GSnyder suggested, but IMO notifications are a somewhat more nebulous way to do it.

Hi Quincey,


Thanks for your patience. Yup, I am aware of KVO and MVC. After watching WWDC sessions about protocol oriented programming and Building Better Apps with Value Types I am trying to force myself to use this type of thinking for my projects to find out if I can find apply them and find any value in them. It sounds like with this particular case I am pushing for something that's not really cut for value semantics and I will be better off using classes.

mixing value semantics and reference semantics with protocol oriented design
 
 
Q