PDA

View Full Version : Archiving Custom UIView




Ides
Aug 7, 2012, 01:09 PM
Hi, I'm new to archiving objects but I'd like to learn how to archive a custom UIView subclass that I have. From my understanding, and the research I've done so far, UIView already implements the NSCoding protocol. Would I use the method encodeWithEncoder:? If so, would I also have to call that on each of my instance variables that my UIView subclass has? Some of the subviews in my view are also custom UIViews, so I would probably have to encode those too, right? Thanks for any help!



dejo
Aug 7, 2012, 01:52 PM
Why do you feel the need to archive your UIView subclass?

Ides
Aug 7, 2012, 02:04 PM
I have a sudoku app and I'd like to archive my view so that when the user renters the app after quitting, the sudoku puzzle is still there. I have a UIView subclass called SudokuTable, and the sudoku table has 81 subviews (9x9) of SudokuCell, another UIView subclass. Each SudokuCell has a textfield for entering in numbers and 9 UILabels for displaying candidates, along with some other instance variables for keeping track of data. I feel like it would nice to be able to simply encode all of this together and then pull it back out when I need it.

Duncan C
Aug 7, 2012, 02:33 PM
I have a sudoku app and I'd like to archive my view so that when the user renters the app after quitting, the sudoku puzzle is still there. I have a UIView subclass called SudokuTable, and the sudoku table has 81 subviews (9x9) of SudokuCell, another UIView subclass. Each SudokuCell has a textfield for entering in numbers and 9 UILabels for displaying candidates, along with some other instance variables for keeping track of data. I feel like it would nice to be able to simply encode all of this together and then pull it back out when I need it.

Don't archive your views. That is a path to spaghetti-code.

Remember, iOS is based heavily on the MVC (Model-View-Controller) design pattern.

The Model is the data storage part of your app. You want to archive your model, not your view.

On startup, your controller object will load the model and display it to the view.

When the user presses the home button, the controller will save the model to disk.

That's much, much cleaner than trying to archive custom views.

Ides
Aug 7, 2012, 03:08 PM
Thanks for your replies everyone, but I actually got it working (and the code is really really short!)

I just implemented encodeWithEncoder: and initWithEncoder: in my SudokuTable and SudokuCell class. I called [super encodeWithEncoder:aCoder] first and then simply encoded each of my instance variables for a certain key. I did the same on initWithEncoder and decoded all my variables. The view shows up fine :)

Actually, there is one problem. An array on one my SudokuTable is not being encoded, it shows up as nil when my table is decoded, even though I did encode it in encodeWithEncoder: ???

dejo
Aug 7, 2012, 04:05 PM
Actually, there is one problem. An array on one my SudokuTable is not being encoded, it shows up as nil when my table is decoded, even though I did encode it in encodeWithEncoder: ???

And thus begins the descent into the spaghetti-code path...

What kind of objects are in your array? Do they all implement the NSCoding protocol? Are you certain you want to maintain that for all possible objects in that array?

Take Duncan's advice: archive your model, not your view. It will be so much better in the long run!

chown33
Aug 7, 2012, 04:20 PM
I agree with dejo and Duncan: archive the model, not the view.

A sudoko data model should be little more than a square array of numbers. That kind of data can easily be stored in a plist (see the NSArray methods that read and write to files or URLs). So if you archived the model-data directly, you probably wouldn't need to write any NSCoding methods at all, and your view cells would automatically be decoupled from the data-storage representation (plist or anything else). Your model-object, which represents the entire array of numbers, could simply write and read an NSArray object using a single NSArray method.

It may be easy to write custom coding methods, but the easiest and most bug-free code of all is the code you don't even write.

Ides
Aug 7, 2012, 08:01 PM
First of all, If it were as simple as storing a 9x9 array of numbers I would use a data model. My app is a sudoku solver. The SudokuCell object has a uitextfield that displays a number, and 9 uilabels for displaying candidate numbers. Each of the candidate numbers can be one of three different colors. It would be kind of hard to save that using a data model. I figured out the array problem, but now I have a new one:

When the SudokuCell unarchives its UITextField, the textfield seems fine. I NSLogged it and it said it's text = "3" (or some other number). However, no text appears in the textview. I know it's on screen because I can tap in it and have a keyboard come up. No matter what I change its text to, nothing will show up on screen.

Duncan C
Aug 7, 2012, 08:43 PM
Thanks for your replies everyone, but I actually got it working (and the code is really really short!)

I just implemented encodeWithEncoder: and initWithEncoder: in my SudokuTable and SudokuCell class. I called [super encodeWithEncoder:aCoder] first and then simply encoded each of my instance variables for a certain key. I did the same on initWithEncoder and decoded all my variables. The view shows up fine :)

Actually, there is one problem. An array on one my SudokuTable is not being encoded, it shows up as nil when my table is decoded, even though I did encode it in encodeWithEncoder: ???

Sure, you CAN archive your view objects, but that doesn't mean that you SHOULD.

Saying it was easy is like saying it's easy to duct-tape the front bumper onto your car after it falls off. Sure you can do it, but should you? It might stay on fine, but what happens if you bump into something?

Archiving view objects to save state data is bad design, plain and simple.

----------

First of all, If it were as simple as storing a 9x9 array of numbers I would use a data model. My app is a sudoku solver. The SudokuCell object has a uitextfield that displays a number, and 9 uilabels for displaying candidate numbers. Each of the candidate numbers can be one of three different colors. It would be kind of hard to save that using a data model. I figured out the array problem, but now I have a new one:

When the SudokuCell unarchives its UITextField, the textfield seems fine. I NSLogged it and it said it's text = "3" (or some other number). However, no text appears in the textview. I know it's on screen because I can tap in it and have a keyboard come up. No matter what I change its text to, nothing will show up on screen.

Dunno. You're not using cells the way you're supposed to, so all bets are off on how it behaves. It's probably an initialization sequence problem (i.e. initWithCoder tries to save values to the text field of the cell before the text field has been added to the view hierarchy, so the data falls on the floor instead of being displayed.)

chown33
Aug 7, 2012, 09:43 PM
First of all, If it were as simple as storing a 9x9 array of numbers I would use a data model. My app is a sudoku solver. The SudokuCell object has a uitextfield that displays a number, and 9 uilabels for displaying candidate numbers. Each of the candidate numbers can be one of three different colors. It would be kind of hard to save that using a data model.

Poppycock. It's just a question of making the right model class. An object (i.e. instances of a class) that holds a number (or numbers) and a small enum for colors would suffice (if I understand your brief description properly).

If you don't know how to make data models that are separate from how the data is viewed, saying that it's hard to save that as a data model is just avoiding the issue. The issue is separating the model object from the view object. The fact that you made cells which combine both data-model and view is clear evidence that it's possible to make a data-model object; simply factor out the data-model parts from the view parts.

If you want suggestions on how to make a data-model, I think you'll have to describe exactly what your cell class is and does now. Without knowing exactly what it does and what it needs to do, no one can design a model.

dejo
Aug 7, 2012, 10:01 PM
Just a word of warning, Ides. The more you ignore the sage advice you've been given and forge ahead with a non-recommended solution, the less support you will find yourself getting from those you seek help from.

Duncan C
Aug 8, 2012, 03:55 PM
Just a word of warning, Ides. The more you ignore the sage advice you've been given and forge ahead with a non-recommended solution, the less support you will find yourself getting from those you seek help from.

I think he's bound and determined to do it the wrong way. We've told him "There be dragons" but he chooses to forge on. I, for one, give up.

I might chime in with an "I told you so" later, mind...

Ides
Aug 8, 2012, 04:54 PM
All right, I took everyone's advice and made a data model. It's just a plist that's stored in the userdefaults, and it seems to be working fine. Sorry if I seemed a bit stubborn, I was just curious about archiving objects and wanted to see if I could get it to work.

Out of curiosity, when would be an acceptable time to use archiving over data models?

Duncan C
Aug 8, 2012, 05:28 PM
All right, I took everyone's advice and made a data model. It's just a plist that's stored in the userdefaults, and it seems to be working fine. Sorry if I seemed a bit stubborn, I was just curious about archiving objects and wanted to see if I could get it to work.

Out of curiosity, when would be an acceptable time to use archiving over data models?


You can archive your data model objects. In Mac OS, for example, it's pretty common to archive the NSDocument object, which is a model object that represents a document.

For a normal application, archiving view objects does not make sense, and is a bad idea.

An XIB file is an archive of view objects. In that case, the structure and setting of view objects is the model for interface builder, so it makes sense.

chown33
Aug 8, 2012, 05:44 PM
Out of curiosity, when would be an acceptable time to use archiving over data models?

Those two things are not opposites. It's like asking "When would be an acceptable time to use singing over biscuits?".

A data model need not be archived (at least not in the NSCoding sense). The things archived need not be data models. Either, or both.

Your issue was one of factoring (http://en.wikipedia.org/wiki/Code_refactoring), not archiving. You combined the data model with the view in a single tightly coupled class (not factored). When the model is separate from the view, it's loosely coupled (http://en.wikipedia.org/wiki/Coupling_(computer_programming)).

You should probably review Cocoa Design Patterns (http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/), especially the details of MVC, so the roles and responsibilities are clearer.