best practices for archiving/unarchiving NSTableViewController data? - objective-c

I have an NSWindowViewController that owns a nib file. One of the objects in the nib file is an NSTableView, managed by an NSTableViewController (also part of nib).
I want to implement the NSCoding protocol to save off all model data, some of which is contained within the NSTableViewController (which I'll refer to as TVC for short). Archiving the entire TVC seems like the wrong answer, since when its unarchived later, it won't be wired up to the nib. And while I could probably rewire everything programmatically...that just seems very kludgy.
I could have the NSWindowViewController grab the table data out of the TVC, but that would mean I would have to expose all of the ivars, which also seems like the wrong solution.
Whats the best way of archiving/unarchiving the data stored within the TVC?

The table view controller should have a reference to the model that stores you data, or if your app is simple you might have that model data stored in an array or dictionary in the table view controller. It is that array or dictionary, whatever holds your data that should be archived, not the table view controller.

Related

MVC: Controller keeps array of model objects or view objects?

I have a view controller placeViewController which pulls in a bunch of Place objects, and from these loads and populates a matching bunch of PlaceView objects which are then displayed as subviews to its main view.
I need to update these views periodically which requires information from the model and other places to be pushed into the views
How should I properly structure this?
Keep an array of Place objects and give the model a PlaceView property to store pointers to the views
Keep an array of PlaceView objects and give the view a Place property to store pointers to the places
Keep both arrays and use a lot of indexOfObject objectAtIndex to jump between them
Some other way??
I need to update these views periodically which requires information
from the model and other places to be pushed into the views
You should really focus on an ObserverPattern. Yours views register to "notifications", and when changes are made, your registered views are notified.
http://en.wikipedia.org/wiki/Observer_pattern
You still can use NSNotificationCenter, but it will not futfill your needs since you need yours views make update per Place object (paired like a dictionary). So i recommend you to implement your own.
It will loose coupled because your controller will just only make glue between the observer and your views, and all the "logic" will be handled by the observer.
Well basvk got the answer in his comment but hasn't posted an actual answer for me to mark correct.
So here it is: "I would create a NSMutableArray with PlaceView objects. And the PlaceView class holds a #property Place *place"

iOS: Create copy of UINavigationController

It is possible, to create an exact object copy of a UINavigationController? I have seen examples of copying objects using copyWithZone:, but I am confused as to how I would use this to copy my UINavigationController.
Any help?
UINavigationController doesn't conform to the NSCopying protocol, so you can't use copyWithZone: or copy on it.
If you are looking to have a customised UINavigationController that you can use throughout the app then you should subclass it and then create a new instance of that subclass every time you need a new one, such as when you create a new modal view controller.
EDIT: If you want to keep the view controllers from a previous navigation controller then you can do something like this (use subclassed navigation controller if needed):
UINavigationController *newNavigationController = [[UINavigationController alloc] init];
[newNavigationController setViewControllers:oldNavigationController.viewControllers animated:NO];
This will do a shallow copy of the viewControllers, i.e. you will have references to the original navigation controller's view controllers, not copies. If you want to do a deep copy on the view controllers then that will be far more complicated and will require specific copying code for each view controller. (See here for more info).
You can do this by creating a category (or a subclass), make the category NSCoding compliant, and add the necessary encoding and decoding functions. You then need to determine what properties you want to encode - the types of view controllers it currently has in its array, and perhaps you'll need to make those objects be NSCoding compliant. You can see that this is not going to be a trivial thing to do, but its not impossible. You may find the solution to your problem is best done using some other techniques.
EDIT: If you want to "duplicate" it, what you really need to know is what viewControllers are in the array. So suppose you want to replicate "state", which in some sense is the same as the original answer but less rigorous. Add a category or method to each object and ask to to give you current state as a dictionary. For the navigationController, that might be just the classes of the objects currently on the stack.
For each of these objects on the stack, you get them to give you a dictionary of their state. By state, its means what text is in UITextFields, views etc, anything that that object would need to go from a startup condition and get back to where it is now.
You package this all up - the nav dictionary and array of the state ones. You can save this as a plist. When you want to construct where you were later, the nav controller can tell what objects to create by knowing their class, then as each one is created it can be sent its dictionary and told "get back to where you were". Once done, then push another controller on the stack.

What is the appropriate UITableView delegation strategy for this situation?

I have a UITableView and I would like all the functionality that comes built into the UITableViewController except that I would like to have the delegate be a separate class. The problem is I need to pull an identifying piece of information from my data source in order for my delegate class to function. Should I make UITableView delegate to UITableViewController, which would then pull the appropriate identifying information, and then just call the third class from within didSelectRowAtIndexPath? I just want to structure this in the appropriate way.
I am fairly new to iOS and objective-C, so I feel like there is a solution that everyone would use, but it is not obvious to me.
I would make the delegate and the data source both point to your custom class. It will be easier to manage table view events all in one place and you really don't need a UITableViewController. If you separate them, there will most likely be heavy coupling between the delegate and the data source as it sounds like you would need to transfer a lot of information between each of them, which defeats the purpose of dividing them into separate classes.
A strategy that I normally use when I have two table views in the same UIViewController and that can fit your needs is to create an Object class for each tableView for example: MyFirstTableViewManager and MySecondTableViewManager.
Each table view manager is set as the delegate and data source to each tableview.
If I need to display a lot of information on each tableview I create properties on each Table View Manager class which I set from the UIViewController.
This way I split the logic of managing each table view to make it easier and keep it clean and from my UIViewController I can set the information to display on each table view by settings each Table View Manager properties and make them to reload its data when required.
Hope this helps you.

Serializing/Storing a UIView and its subviews

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.

Core Data: When and where are Entities loaded in the first Place?

I have a question about Core Data. When starting my appliction, when is my data (which is stored automatically by Core Data) loaded into the NSArrayControllers? I want to modify it in the first place before the user can interact with it.
To be more specific: I have an NSArrayController for the entitity Playlist. Before the user can add new playlists or interact with the app at all, I want to modify the playlists programmatically. I tried windowControllerDidLoadNib: in my NSPersistentDocument (MyDocument.m) and awakeFromNib both in my NSPersistendDocument and the NSArrayController, but when I check in these methods with [[myArrayController arrangedObjects] count] I get 0 as result (the array controller's content is empty).
However, I actually have data stored and it is displayed to the user. I just do not know when and where I can modify it in the first place.
Thank your for any help.
Data is never "loaded" into the NSArrayController. The array controller is not an array itself. It does not contain or otherwise store data.
Instead, the array controller queries the object it is bound to for specific pieces of data only when that specific data is needed. This is especially true of Core Data in which managed objects are only fully instantiated when their attributes are accessed. The array controller moves data from an array type data structure to another object (usually an UI element.)
If you want to modify an existing store before it displays in the UI, you need to process the data before the array controller used by the UI is even initialized. If you're using NSPersistentDocument, then you can override readFromURL:ofType:error: to fetch and modify all your objects when the document is first opened. Alternatively, you can override the window controller's windowWillLoad or showWindow methods.
Regardless of where you do it, you must fetch all the managed objects you want to modify. You could programmatically create an array controller to do this but a fetch request is easier to micro manage if you have a large number of objects to modify.
You could try observing the "arrangedObjects" keypath of the controller and adding some logic to work that your array controller has been populated for the first time.
Another possible hook is implementing the awakeFromInsert/awakeFromFetch methods of your managed objects.