willDisplayCell:. might be faster, consider also it’s not necessary to refresh the whole table view.
There are methods to refresh only an index set of rows.
I’d like to repeat the option to use a custom class instead of pure dictionaries and move some intelligence into the instances.
The standard dictionary fits perfectly here, as there is only an “AS Record” storing four keys. The rebuilding of the color table takes a non-mesurable time (there are only four or five colors, and I doubt there will be more.
The problem is elsewhere. The ASOC version of the matrix was much more faster (I just can’t understand why).
I’ve started reading about Core Data and, to put it briefly, I’m not ready to wrestle with it. I don’t even seize the notion of “context” by now.
I suppose my matrix is updating much more as needed. Some operations are called repeatedly and uselessly, but which ones? is there a “basic” draw method for the NSButtonCell that I missed? I just want to set the background color and nothing else. Do I have to validate a region after drawing to prevent useless redrawing? When the matrix is drawn for the first time, 4096 custom cells are initialized, they look at the color table and draw in half a second! Then, if I change one single cell, it takes more than 5 seconds.
I’m still lost. And here comes the time I begin to change all the design and nothing more is working. :o
PS: there is no “willDisplayCell.” method for the NSMatrix.
It simply does not speed up, whatever I try to do.
For these of you who have tested it, is a NSCollectionView faster than a NSMatrix? I have seen two or three examples, but of course they show how to put nice things in the collection, like buttons and icons, so the simple of the NSCollectionView is a bit masked by the complexity of the result: sorting icons, resizing windows, gradient background.
I just want a collection of 64x64 square views, which just set their background color and draw nothing more. Usually, examples show something simple and let the user make something more complex – here I have complex examples that I need to simplify.
So, question: for the grid I want to implement (fixed to 64x64, no resizing, no scrolling) what is the best class: NSMatrix or NSCollectionView?
Help me, please, because I’m running out of sleep :rolleyes:
I can’t quite see what you’re after, but this bit of the docs strikes me as pertinent:
The only other suggestion I’d make is to consider a single subclassed NSView, with its drawRect: doing all the work. You might even want to look at Quartz 2D.
I’ve worked with custom NSMatrix in the past and custom cells without problems. When matrices become noticeable slower you’re doing something wrong (with cells). Your posts are still too general for me but the most common problem is subclassing cells. The advantage of a cell is that it can display itself on the screen hundreds of times per second without problems and without needed to copy or instantiate itself (the drawback of a view).
I’m pretty sure I make something wrong: the first time the NSMatrix is drawn, I make (for testing) every custom cell set its background to [NSColor blueColor]. The result is: the matrix is drawn quasi instantaneously! And there is nothing more later: I select some cells with the mouse, like this:
-(void) mapClick{
int theTag = [[[[mapController selectedObjects]lastObject]objectForKey:@“colorRef”]integerValue];
for (id aCell in [mapMatrix selectedCells]){
[aCell setTag:theTag];
}
}
Setting the tag is (of course) very fast again. Then. the matrix begins to resemble to an asthmatic sloth, as there was intensive calculations or memory operations, which shouldn’t be.
To Shane:
implement such a NSView subclass (the matrix as a whole) with a sort of “square pencil” to draw the “cells”, using a memory matrix to retain the colors (sort of mapColor [0…63, 0…63]) was the solution I used, but it was 20 years ago in procedural Pascal. I was hoping that Cocoa could preserve me the redo such a thing.
Should I post the whole program? It is not so big. Here is the custom cell:
What’s wrong with my subclass? If there a way to make things simpler, I’ll take it.
I just downloaded and tried it. It can’t be possible: Quartz Debug just blinks again and again when I click on the matrix. It is not redrawn twice, but quasi permanently! What makes the NSMatrix constantly redraw itself?
Not SO far anymore. Hey, this thing is incredible! Aaron Hillegass’ tutorial on the bases of Core Data is very clear, I like this step-by-step exercises with screen shots.
All you can have for free (incredible, you even get multiple Undo/Redo) makes me just want to rewrite all my applications using this framework!
But alas, this does not solve my matrix problem. I look toward Quartz now, it reminds me vaguely of the old world QuickDraw, when I had to do everything myself to make it work faster on a Mac Plus…
Any ideas for what I’m doing wrong into the code above? The other sites remain silent too.
Shane, I’m on my way. A 20-years old idea is back to life! Of course this idea will cost me a few extra work, like learning Quartz. This is a beginning:
This lovely little thing draws 4096 “virtual cells” in a non-humanly measurable time! The C matrix is used for the color reference.
Maybe I should rebuild a “color array” before drawing, but as “objectAtIndex” method is very efficient, this is not true optimization.
And now: how to get a point clicked into the view, determinate which “cell” was hit, and set the gridData matrix to the correct reference (that is, the selected color on the controller’s list). Quite an interesting exercise.
If someone is understanding what I’m doing (it’s a “paint module” using a grid of 64x64 colorable cells to figure a map) and has a better idea (I mean maybe there is something in Quartz which allows to do this more easily) you are very welcome.
Each object in the array controller represents one cell.
Each cell is an instance of a custom class containing the key/value pairs of your dictionary.
Additionally it contains an instance of the view (just for the cell, not one view for the whole grid),
the place/coordinates in the grid and a tracking area to detect mouse clicks.
¢ Shane’s solution is quite easy to implement – in fact, it working perfectly now, I just did this:
Even if you click into the “last” cell [63,63] it is redrawn without delay.
This “bitmap” approach offers the possibility of using tools like rectangle, ellipse, paint bucket.
¢ Other solutions (like yours): a custom view, with an instance variable (NSArray) holding custom views. These views are placed at initialization and may receive clicks directly. Not bad! Each view may hold the very minimal instance variables (tag, for example, is “pre-implemented” in NSView). But tools are less easy to implement.
I’d like to submit a problem to the MacScripters Gurus (who allowed me to learn so much in a very little time and don’t hesitate to provide precious fragments of working code):
For the moment this “map” is a little test app by itself (it does not do more than present a blank map, allow colors to be defined, then used to fill map’s cells, and finally saved to disk and reloaded.
The next step is to make these objets a part of a Core Data application. So: Core Data is not for the faint hearted, it gives a lot but you have to follow the rules. For instance, data structures (attributes) are managed by array controllers. I already tested a multiple-controllers application (with customized controllers) which works well, excepted that a tiny zombie rascal :o is crashing my app when the last window closes (see my other post).
But whatever structure I choose finally, it has to be compliant with Core Data.
So what would be the better solution? With NSArchiver I can store what I want, but Core Data is more strict (or I missed something).
So each “cell” has now its “color reference” (I want each color to be editable, so I only keep a reference to it).
In the Core Data document, I create the matrix, and I get the colorReference by the synthesized accessor. I create a dummy ArrayController just to hold this array and to be “Core Data Compliant”:
That’s it. Well, it’s a sort of hybrid structure of Core Data and Quartz, but it should work.
I suspect this is a problem with my Core Data entity. I defined an entity called “Map”. It has three attributes:
scale : NSNumber with NSFormatter (mandatory if you want a NSNumber instead of a NSString, which >bangs<).
units : NSString
mapData : Binary Data ???
This mapData attribute causes a problem. My custom view (“matrix” property) stores its color references into a NSMutableArray. This is the array I want to put into the mapData attribute. But this does not work:
Ignore everything but the “lastObject”: this is the (single) Map entity.
[matrix colorReference] is the (property) NSMutableArray.
Now, to simplify: I want the NSMutableArray to become the “mapData” attribute of the Map entity, to be stored when the doc is saved, and later retrieved and transferred to the custom view. The design is clear, the way to do it much less.
Shane, I think there is a lot of people on earth that knows much more than me about Core Data.
This framework is a trap : you follow the tutorials, like “recipes”, “department and employees”, everything seems simple as long as you stay in IB. One tableView here, some simple bindings there, “entities”, “attributes” are not so scary, you do not worry too much about these complicated words like “managedObjectContext”, you paste them in the right place, and you marvel at an interface that runs by itself.
And then you want something a little more personalized, you start coding, and you begin to regret very quickly NSArchivers…
You realize that literature is enormous, that the sites are full of questions about iOS (this iOS frenzy…) and that the only ones who could help are experts who say “it’s simple, just…” . Others, like me, go bump in the night, under the pale light of the docs from Apple engineers.
Core Data’s attributes type may be the “standard” ones (strings, numbers, dates.). For the “less standard” attributes there are built-in transformers (images, attributed strings). I’m not sure about arrays, so I have to serialize it myself: I’m using NSArchiver/NSUnarchiver to transform the color reference NSMutableArray into/from NSData. The attribute type is “Binary Data”.
It works well, but it has a smell of “Do It Yourself” coding. I’m not really satisfied with this solution.
A more proper way would be a subclass of a unique NSManagedObject, which could initialize on demand, store and deliver the data into the “awakeFromFetch” and “willSave” methods.
An even better solution would be to “connect” the two properties (entity attribute and NSView NSMutableArray), either by addObserver or via a NSValueTransformer, I don’t know how for the moment. Or maybe the built-in transformers of Core Data would do this job for me. the docs are still unclear for me.
Anyway, I’m still looking for the best (read: elegant) solution for implementing this design. I’ll keep you informed.
You’re certainly right. I’m now moving ever more “intelligence” into specific subclasses, and my app looks a bit better object-oriented that my former ASOC version (where my BASIC-looking appDelegate was doing all the job). I have now objects that talk to each others, and everything is KVO compliant.
It’s particularly handy to give my subclasses Outlet properties and interconnect them in IB: it saves a lot of code (testing if an object is the good one, setting and getting variables, of accessing values with ugly code like [[[[myController arrangedObjects]lastObject]setValue: newValue to key:@myKey], using observers, and so on.)
Thank you for having supported me in this way.
Core Data lends itself particularly to do so: because the framework manages the “basic” housekeeping like instantiating, reading and saving the files, and multi-level undo, the document delegate is very, very. empty. A lot of things is updated “magically” by bindings, so the real work (which cannot be avoided) is made “internally” by the subclasses, which operate directly on themselves, as it should be in OO programming.
And of course, without talking about reusability, you may be confident that “ok, this piece of code works, leave it alone and concentrate on something else.”
EDIT: Yes, built-in transformers DO the job: an NSMutableArray may be automatically serialized if the attribute type is set to “Transformable”. Great.
Now for the connection. Without this connection, the NSMutableArray transferred to the NSView is not KVO.