Search code examples
c++objective-cmodel-view-controllerboost-signals2

Connecting C++ Model to Controller with Signals2 in Objective-C/C++


I'm developing a cross-platform C++ data model with almost 1,000 different kinds of data items (but < 100 different data structures/classes). To handle the Model to Controller messages (i.e. notification for the Controller that some data item has changed) I'm thinking about using boost:signals2. I think this will help create a unified Observer pattern that remains the same across different OS platforms. Initial implementation is on Mac OS / IOS, with subsequent UI developed on .net and unix.

Questions:

1) To set up observation of the data model, what type of object should a Controller connect to the signals2 object/slots? Should there be specific functions/methods/selectors in the Controller for EACH data item observed? Should these functions be C, C++, or Objective-C/C++ functions?

2) What level of granularity should a signal have? Should each item of data have its own? Or should the Model's management of related structures/records maintain a single signal for each type of structure/record? For example — should application preferences have ONE signal for all preferences data — passing information about what data item was changed?

3) Should the process of sending signals (or the slots receiving signals) be performed in a SEPARATE THREAD?

4) I understand Cocoa has its own system for Key-Value Observing. But would such a system be advantageous to COMBINE with the Model's signals2-based Observer paradigm — or just redundant?

UPDATE:

Regarding "granularity" of actual signal2 objects (not observers), I think having one per document and one for application prefs might be a good place to start. My document data already has a "key" concept, so it may be possible to generalize common UI cases where a UI component is tied to a specific item of model data.


Solution

  • There are quite a lot of facets to this question, so I'll tackle what I can.

    Why do we want to be able to observe something in Objective-C and .NET?

    I think it's instructive to think about why we'd want to observe a data-model in a 4th generation language? Aside from decoupling subsystems, we can also bind UI interface elements directly to the data model in some cases, avoiding the need to write a great deal of code in the controllers. This is possible in a WPF application built on .NET and in AppKit on MacOSX. There are fewer opportunities in UIKit on iOS.

    Meta-model

    The first obvious thing to point out is that two of the language run-times you want to target (Objective-C and .NET) provide language-level implementations of the observer pattern which are built around object properties. If you want to integrate them without writing thousands of lines of boiler-plate code, you will want to do this too.

    This strongly suggests that all of your C++ model classes need to inherit from a meta-model that provides a generic property mechanism. Wrapped up with this will be an mechanism for observing them.

    The alternative will be to generate an enormous quantity of boiler-plate setter/getters in C++, and binding objects to make use of them in .NET and Objective-C.

    Adaptors

    For both .NET and Objective-C you would design a generic adaptor class that uses reflection to do their dirty work. In the case of Objective-C you do this by overriding methods in NSObject to forward property sets/get messages onto the underlying model's property mechanism. I believe in .NET you can use reflection to inject properties corresponding to those in your model into the adaptors.

    [Aside] IDL/ORM

    Surely by the point you have a data model built on top of a meta-model, you might as well use some kind of IDL or ORM to describe and automatically generate the very large number of model classes? The huge number of classes you are dealing with also suggest this too.

    Granularity of Observers

    In terms of granularity, you could do either - it really depends on the way in which your data model changes and the UI needs to react to it. KVO in Objective-C is designed around changes to named properties on an object, but is restricted in that an observer has a single delegate method for all objects and properties it observes. This is, however, only an issue for your Objective-C UI components.
    Integrating with this is definitely worthwhile unless you want to write masses of adaptor methods for value-changed events that bridge between C++ and Objective C: Remember that whilst there is toll-free interwork between C++ and Objective-C++, objective-C++ classes can't inherit interfaces C++ classes, not can you send a message to an objective-C object from C++ directly without a bridge and some nasty casting in an objective-C++ compilation unit.
    With .NET you'd probably get into all kinds of similar machinations with an intermediate managed-C++ layer.

    Threading

    The only sane way to do this involving more than one thread is to queue signals for processing on the UI thread. After all, if generating signals in another thread you'll need to do this at some point later to update the UI. Using a separate thread for model and View/Controller portions of the app sounds like a recipe for dead-locks. It'll also be very hard to debug the source of a signal it it'll be long gone in another thread. Your life will be much easier keeping it all on one thread.