Serializing/Storing a UIView and its subviews - objective-c

I'm a relatively new iOS developer, with most of my previous experience coming from .NET.
My application is a canvas like system in that there is a parent UIView that contains all the objects the user is placing/resizing/etc as subviews. I want to be able to save these positions/configurations to named files.
In .NET, I would have simply subclassed UIView, given it a "title" property, then serialized this to file, and then deserialized them to load them back, but in Cocoa I'm quite lost.
Originally I thought I could do this using NSCoding, but this doesn't seem to be a good solution for multiple file saving.
So I looked at Core Data, but I'm not sure how I can create Core Data objects of existing Cocoa UIKit classes like UIView.
I've spent a while googling and can't find any information about this kind of predicament.
What should I use, and what is the best way to go about it?

You probably could do it with NSKeyedArchiver, since UIView implements NSCoding. A more MVC-oriented design, however, would be to have the user manipulate a data model by moving the views around. To save, you'd archive the model rather than the views themselves.

Related

associate model data pointer with NSWindow

I have a MacOS appkit app with a LOT of different NSWindows (hundreds), and they are each created from storyboards.
Many of these NSWindows have container views with complex embedded view/view controller hierarchies.
During initialization, it's necessary to know the model object associated with any given NSWindow, so its subviews and controls can be properly initialized. Since any NSController can know its NSView, and any NSView can know its NSWindow, it would be nice for that information to stored with the NSWindow.
It would be great to set a "representedObject" for the NSWindow, but unlike NSViewController, it doesn't really have one.
Is the only real solution to create a simple custom class (derived from a small base class) for each and every NSWindow storyboard object, so NSViews & NSViewControllers down the view hierarchy can get to my model data (pointer)?
A CLARIFICATION: very few of my NSWindow objects in our hundreds of storyboards have custom classes or code derived from NSWindow. So while a Category is definitely helpful for adding an API to classes to ACCESS the model data associated with the NSWindow, it's not helpful in creating a property or instance variable and initializing it in all those NSWindow storyboards.
ULTIMATELY I PRESENT A SIMPLE BUT DISGUSTINGLY BAD SOLUTION NO ONE SHOULD COPY:
Our app does not use NSDocument, which would provide a facility for associating NSWindow objects with a document/model architecture. So our goal has been to allow each and every NSController and NSView to get access to the appropriate singular document model object required to initialize the view's controls.
I've been warned by Apple engineering gurus that I cannot depend on the order in which views and subviews are created and initialized. That makes passing data down into complex storyboard embedded subviews tricky and error-prone.
But -- with all UI on the main thread, it is not possible for a single application on MacOS to create, initialize, and display one storyboard AND have another storyboard initialization & display interrupt that process (at least not our user-invoked application storyboards). So the simple solution is...
...to have a temporarily set application-level global with the desired document model pointer. That, and a stack-based lock count to insure that the above assumptions are never violated. Terrible design. Efficient solution.
No one needs to remind me WHY this is not good. But if there's a better solution it has escaped my testing. I found that even viewDidLoad and viewWillAppear can't be trusted to have a solid pointer back to its NSWindow...
Without knowing your application structure; you will need a mechanism to assign the model pointer to each individual window. This will necessitate adding some code somewhere. An NSWindow subclass does seem appropriate.
In the AppKit MVC pattern, model data usually fits between the view and the view controller. Attempting to associate the model with the window is fighting against this pattern to some extent.
That being said; the Objective C runtime does allow you to add custom properties to existing classes using categories. This is achieved using Associative References. The relevant functions are:
objc_setAssociatedObject
objc_getAssociatedObject
objc_removeAssociatedObjects
This article has a good rundown of the benefits and downsides of that approach.

How does user input fit into Apple's MVC pattern?

I'm a little confused about input processing in regards to Apple's MVC pattern. According to Apple, your objects should be divided into model objects (which handle the data), view objects (which display stuff), and controllers (which bind the two and also process events and input). However, many of Apple's native UIKit views — UIScrollView, UIControl objects, etc. — do all the input processing themselves, possibly letting their controllers know about it via delegates and data sources. This really confuses me. In my mind, the sturdiness of the MVC triad depends on both the model and view being fairly dumb (and thus easily swappable). When all the OS-level event complexity is centralized in the controller, you have a very nice separation of concerns. On the other hand, adding input processing to the view seems to turn it into a sort of controller of its own.
Am I missing something here? What's the correct way to think about this?
User Input is part of the View in the MVC pattern. They directly interact with the user and provide their data, either on request or through delegation, to a Controller, which might then use that input to affect changes to the Model.
"Dumb" and "easily swappable" are not necessarily the same thing.
Buttons contain a lot of functionality that we don't want to rewrite in every single controller: tinting of the image to indicate highlighting, allowing for cancellation if the tap strays a certain distance before touch-up, etc. Scroll views contain a lot of physics.
In other words, "which display stuff" is a mischaracterisation of view objects. UIView -- the base class -- just provides event data, but subclasses provide higher-level data such as "the button was tapped" or "the scroll view decelerated to a stop".
One thing to think about is your perspective.
When most of us code, our Model is a data object (maybe backed by files or databases, etc), our View is a UIView (possibly setup/configured in Interface Builder) and our Controller is the UIViewController.
What if you weren't coding an app though? What if your world was a UITableView? You can still have a basic MVC separation. Your Model is represented by the UITableViewDataSource protocol, your View still a UIView with it's setups and configurations and your Controller is the UITableViewDelegate protocol. All the pieces there and even separated, the separation is just different than when using a UIViewController. You can see a practical example of the separation a data change. When you the data in the data source protocol nothing happens. You have to call a reloadData method on Controller bit for the table to realize data was changed.
The smaller the item, the harder it will be to see the MVC pattern. A "button" would be a lot harder to use if it was broken into 3 different objects, but you can use MVC patterning inside a single object to create well encapsulated. A UIButton has it's Model in the form of a both public and private properties, a View (UIView still) and a Controller which is bunch of code that accepts events and makes modifications to the View and/or Model as appropriate.

Looking for good guidelines on how to manage code for large UIViewController classes

I've been working on my first XCode/iOS project and so far it's been an enjoyable experience. Currently, I am working on a Nib file that acts as a primary display for other views. Within this Nib file, I have a primary UIView and next to it I am designing a series of seven other views. At runtime I swap these seven views in and out when necessary, within a container UIVie, located on my primary UIView.
Across my 8 total views that I'm designing in IB, I have a large amount of buttons, images and other objects that need to be linked to IBOutlets. As this project is getting bigger, it would helpful if I could split my class across multiple code files.
Using categories is the solution, however, I've hit an annoyance-- when I tried to create an IBOutlet in one of my category headers, the XCode compiler keeps giving me errors and warnings about ivars and outlets. In my Nib I have a large number of objects that need outlets and I'd prefer to not have to define all of them in one, huge code file if that's possible.
However, I understand that I have to work within my limitations, so my question is a bit different than asking how to add an IBOutlet to a category. Instead, I'd like to know what are the best practices for splitting up a large UIViewController class across multiple code files? What are the limitations of objective-c and what is the best way to structure your code when working with interface design?
My code is not quite yet unwieldy, but I'd really like to start restructuring it so that it will be much more manageable when it consists of 100's of methods and 1,000's of lines of code.
Any pointers would be helpful. Thank you!
You can create one NIB that contains several controller objects, each managing the relevant views, and that will help to keep your code more manageable. The downside is that your memory footprint is larger loading a large NIB.
To achieve this, define the controllers in separate classes with relevant IBOutlets, and then drag the NSObject from the objects tray (where the UILabel, UIButton etc... are) into IB. Then for each object, define its class to the the correct controller, and you will have access to all the correct outlets and actions. You can then hook the controllers into a single UIViewController to control how they interact with each other.
The preferred way though, would be separate NIbs for separate controllers, and to have them all as UIViewController subclasses. If you move to iOS5 they have superseded NIBs in IB with Storyboards. These allow you to have separate UIViewControllers in a single IB file, however they are more efficient in memory usage as they don't keep the whole object tree in memory.
This is a pretty loaded question. But, in my experience, I've found that IB causes more headaches for me than it's worth in complicated situations such as this. I recommend just forgetting about IB for this scenario and just create your views in code. IB is really supposed to alleviate some of the more mundane tasks of layout, style, etc.
I recommend that all of your views be placed in their own project files as this has paid off for me...nothing more painful than scrolling through 1000's of lines of code to find what you need...and worse yet, using that dreadful code collapse widget in the gutter.

When do I need to subclass UIViewController and when can I just instantiate it?

I am learning iOS programming through the Big Nerd Ranch guide by Hillegass and Conway. I’m writing an app of my own as I go through the book, and one of the questions that has been bugging me is exactly when I need to subclass UIViewController (and its ilk) and when I can just instantiate it.
For example, my app consists of generic building blocks: the interface is tabbed, and the tabs lead to a UITableView, a UINavigationController that creates UITableViews, and so on. Following the book’s instructions, I have subclassed UITableViewController to create the table views. However, in creating the UITabBarController that contains all of my app’s content, it seems sufficient to instantiate a UITabBarController and then add a bunch of views to it. (All of this is done in the application:didFinishLaunchingWithOptions: method of my app delegate. Since most of my app consists of simple combinations of basic UI parts, I’m trying to do build the UI programmatically whenever possible.)
I get the impression that what I should be doing is creating a subclass of UIViewController (or UITableViewController or whatever) for every interface in my project. This seems weird to me, since most of these classes would only ever be instantiated once. Am I just misunderstanding how OO should be used in this case? (I have a good amount of programming experience but relatively little has been with OOP.) Should I be creating a subclass for each and every screen that the user will see?
Should I be creating a subclass for each and every screen that the user will see?
If each view requires different logic, yes.
Don't shy away from creating new classes for conceptually separate things. Programmers coming from non-OOP to OOP might feel that a file with only a small amount of code is a waste. Suppress this feeling. Classes are cheap, and help enormously to organise your thinking.
So you have two types of UIViewControllers in iOS. "Container" viewControllers and "Content" viewcontrollers. Both are subclasses of UIViewController but have very different purposes.
The Container type is what the UINavigationController and UITabController are. They are rarely subclassed and typically used as is (in fact, I believe Apple doesn't allow the subclassing of UINavigationController at all). These "Containers" take care of moving "Content" view controller around for you. They do not have much content of their own, beyond adding things like a tab bar or a navigation bar.
The "Content" view controller are the ones you create most of the time. You will rarely be able to use a UIViewController as is, because it will not have any functionality. That is why you subclass them. These are meant to represent a single "screenful" of content. So in effect, every "screen" the user sees should be controlled by a UIViewController subclass.
The UITableViewController is simply a specialized sublass of UIViewController that already contains some methods for managing tables.
The way the UIKit framework was designed was for you to use subclasses of UIViewController to display content and to use out-of-the-box "Container" controllers to facilitate the management of your UIViewController subclasses.
You need a subclass of UIViewController if you want to do any of the following (not an exhaustive list, but some examples)
customize the view hierarchy when the view hierarchy is loaded (in
viewDidLoad)
provide some behaviour as the view controller's views become visible
(or not) (in viewWillAppear:, viewDidAppear:, viewWillDisappear:,
etc.)
clean up after yourself as needed in viewDidUnload
create outlets to views in the hierarchy so you can adjust them as
needed in the above lifecycle methods
My reasoning behind subclassing UIViewController, and other classes is that:
Almost always you must initialize variables and assign values to the instances of classes. You add subviews and set their frames, define actions for the UIViewController instance, etc. If this UIViewController instance is directly from the base class, its initialization should be done outside of it. If this initialization is required at different places for multiple times, you may have to deal with repeated initialization process.
So, you've compiled these processes into a method, making it reusable from wherever this UIViewController instance is used. But where do you want to put it? Don't you think it's much better to put it inside the subclass of UIViewController? Also, you don't even have to come up with specific name for this initialization method. Just override the default -(id)init from the super class.
Though you may think it's suffice to use UIViewController without subclassing it for now, as your project grows, it will be challenged to deal with reusability issues. Take some time to look at your codes. Check if there is too much repetition for such as initializing an object, or assigning values to it. If you are doing same things with an instance of a class in multiple places, compile them into a method to be reused. And as number of such methods grow, you will find the need to use subclass which will contain these relevant methods for the instance.
No matter the size of your project, using classes to distinguish different objects is important. Almost always, the basic essential classification is done by the framework, making it unnecessary to introduce new concept for a class. However, this doesn't mean the framework also knows how your project and its objects can be classified into. By using subclass, you can utilize every benefit the development framework can provide and still keeping the objects in your project to be as unique as possible, based on the purpose you've designed for them.
Well about the UITabBarController you are right. There is no reason for you to subclass anything if the default behavior is sufficient. However once you need to do some custom things you will need to subclass it..
Also, why are you trying to build the GUI programmatically? For the learning curve? There is no real reason not to use InterfaceBuilder, it saves you a lot of time.
You should subclass the UITableViewController in order to get your data in the view, that is how the MVC model works. The default implementation does not offer anything in order to get your data in the view, I don't think they will ever do that in order to make sure that nothing is wasted, their 'connection' to the model object might be different from the one you want and you would end up writing an adapter if your model object is not compatible.
I hope this will help you out a bit.
And merry x-mas.

MVC with cocoa/objective-c

I have a strong j2ee background, and I am trying to move to objective-c for some desktop/iphone programming.
I used many java web frameworks with mvc in mind, spring and struts ecc... so I am used to have servlet or controller which pass attributes to jsp pages, which is the view.
In jsp pages with jstl you can call this attribute and render to video.
In this way controller and view are (in theory) clearly separated.
With xcode, I can easily recognize the controller and the view built with IBuilder.
All the tutorial I found, shown the controller which go and change directly labels or text fields.
So my two questions:
seems to me that there's no separation between the two (controller and view), where I am wrong in that ?
is there a way for a controller to pack all objects in a kind of context in a j2ee way and have the view read that context ?
thanks
Leonardo
In most of the examples you have read you probably saw something like this:
[myTextfield setStringValue:myString];
now in this case sure the controller is updating the textfield directly, however as myTextfield is usually an IBOutlet it can be any textfield in your view, or even nil. quite possibiy it doesn't even need to know that it is an NSTextfield just that it responds to a setStringValue method. In this sense there is a seperation between the controller and view.
Now in your comments above you were concerned with seperation of responsibilities within MVC but did not mention the model much. With Cocoa bindings you can bind directly to model keypaths, in this case the model neeed not know anything at all about the view.
MVC is a bit of an ambiguous concept with no hard definition. It can mean different things to different people. For me it means that the view has knowledge of the controller ( through outlets or bindings) limited knowledge of the model(through bindings). The contoller has full knowledge of the model and limited knowledge of the view(through outlets). Finally the model has zero knowlege of the view and ideally no knowledge of the controller.
With regard to your second question, I don't use j2ee, but I think you can acheivee what you want by having your controller update a context ivar ( probably a NSDictionary) then in your view bind to this context with a keypath. However there is no real need to wrap everything up bindings are very versitile and u can bind to any property.
I do not understand your second question (I've never used J2EE), but I think I can make some headway answering your first.
Cocoa does not enforce MVC; it just strongly encourages it -- especially for larger projects. Consider an example program, one that has an NSTableView bound to an NSArrayController.
In this case, the NSTableView is clearly the view (it has the word "view" in its name) and the NSArrayController is clearly the controller (it has the word "controller" in its name).
The model is an NSArray that the NSArrayController knows about, but you probably don't interact with that model directly. You will instead ask the NSArrayController to manipulate its model by sending addObject: and removeObject: messages to the array controller (and not to the array itself).
When you do this, the NSArrayController will effect a change in the NSTableView via bindings. Again, you don't ever ask the NSTableView to do anything.
So you never talk to the view and you never talk to the model. Everything you want to happen goes through the controller.
MVC. QED.
Of course, maybe the way your project works, the view should be its own controller. The world won't end, although you might find it to be a little more difficult to go against the grain of the framework. But you should always try to use the best approach for the job at hand instead of insisting on some sort of design pattern purity.