MVCS vs MVC


#1

Hi,

I’m not clear how MVCS is noticeably different from MVC. From the point of view of an app, isn’t the Store part of the model layer?

Thanks.
Jim


#2

Without trying to put this into my own words, I feel that the book answers your question very clearly.

If you go back to page 292, and read the section titled “Model-View-Controller Design Pattern”, this should hopefully clear things up for you.

Nick
http://myfirstiphoneapp.co.uk
http://easyintervalsapp.co.uk


#3

Thanks. I had seen that, but in all of the cocoa and webobjects work that involved backend access through Enterprise Objects Framework, we had all persistence and retrieval logic in the EOF layer, which we considered “The Model”. Conceptually it seems like the model == the data model, and in OOP terms that would include the methods that persist and access.

Thanks.
Jim


#4

I’ve heard it called a number of things, most recently, the “service layer”. I think conceptually they are probably all very similar. This is just a pretty general purpose implementation catered to iOS.


#5

I agree with the original poster. I’m surprised by all the verbiage in the book dedicated to hammering on this MVCS idea as if it’s something new and/or difficult to understand. ? It’s unnecessary. The idea of creating an object to handle network stuff in the NerdFeed project should be obvious to OOP programmers. One sentence stating “Now we are going to create an object that handles all the internet business so we can get it out of the view controller, because it doesn’t really belong there” would suffice.

I think it’s pretty much standard OOP. The only difference I see (if I’ve understood the concept) is that you seem to be pushing the idea of a singleton master (the “store”) that spawns “actors” to do work, whereas it would probably be more conventional to design autonomous worker objects that are ready for multiple instances without a master. There may be cases where the singleton model makes more sense, but for example in the Homepwner project, I thought the MVCS idea led to unnecessary objects and weird structure; I just mean, the same app could be done using fewer objects and it would be easier (for me anyway) to keep track of.

Don’t get me wrong – you guys are great! The programming structure in the book is well done, interesting, and all that good stuff.

One thing I thought was missing from Chapter 28, a brief discussion of synchronous versus asynchronous behavior in iOS and how it differs from OSX. But I still have a few chapters to go …

Thanks!

EDIT: Thinking about this a little more after finishing the book, I don’t see how the Store concept could possibly be anything new. It’s just an I/O module. Instead of calling it a “Store” (which sounds strangely commercial to me) I’ve always called such objects “IO”. Making an object to handle file/data Input and Output is a new concept for iOS programmers? I doubt it. But kudos for encouraging everyone to use IO modules. If you feel it challenges something in MVC, then by all means preach MVCS. I’ve been programming since the 80’s, made the change to OOP some 10+ years ago, and I can’t imagine making apps without IO modules, but maybe that’s just me?


#6

The singleton approach makes more sense when applications get larger and there needs to be a gatekeeper for caching, combining or manipulating the data.


#7

I agree with muz1kt3ch. Store pattern is good, but over-using the Singleton can lead to trouble. Consider an example where two asynchronous actions need to be taken in serial. You ideally only want your view controller invoking a single store to encapsulate the full process instead of using 2 separate stores. If you have 1 store you need to maintain some state between the two calls. The only way I can think to do it with a singleton would be to chain the calls within your completion block:

- (void) doStuffFromTwoServiceCallsWithCompletion(BlockType) block
{
     NSURLRequest * req = [NSURLRequest requestWithURL:url1];
     MYConnection * connection = [[MYConnection alloc] initWithRequest:req];
     connection.completionBlock = ^(id obj, NSError * err) {
        if (!err) {
              NSURLRequest * req2 = [NSURLRequest requestWithURL:url2]; // assume this includes something in the first service call result, which is why their serial
              MYConnection * connection2 = [[MYConnection alloc] initWithRequest:req];
              connection2.completionBlock = ^(id obj2, NSError * err2) {
                   block(obj2, err2)
              };
              [connection2 start];
        }
        else
            block(nil, err);
    };
    
    [connection start];
}

This gets messy quickly. Is there a better way with a singleton? I agree with the point about caching, but I would then create a separate singleton that just encapsulates the cache. From what I understand, NSURLConnection itself operates similarly in that you create individual instances of it which is backed by a shared connection pool.


#8

Hi ranger27 - can you elaborate on your last posting? I’d like to better understand your point about multiple asynchronous actions in serial. Is the method you provided meant to be a method on a singleton store class? I see how the nesting blocks is a little messy but I’m having trouble understanding what the cardinality of the store object has to do with this. Perhaps you could post a similar example of how you would prefer this use case to be written if you weren’t using a singleton?


#9

The issue is that with a singleton you cannot safely hold a callback block or other instance variable. The method I provided was meant to be within a singleton store object. Because you cannot hold a reference to “block” (the input variable in my method) within the object, you must keep passing it around via the connection object. There are ways to make my example somewhat more maintainable (like having your block do less directly, and just invoke another method on your singleton), but the point is that you’re doing quite a bit of work just in the name of maintaining a singleton, when it’s not obvious why that’s the case. Instead I would suggest that you create an instance of your store like any other object. If you need to maintain shared state across instances you can use a static within your class or, as I suggested in the previous post, use a backing singleton for a cache. This also simplifies the interface that has to be implemented by the consumers of your store.