开发者

Using NSView instances as NSDictionary keys?

开发者 https://www.devze.com 2023-01-28 19:38 出处:网络
I\'m trying to create a semi-complex set of view animations (think an animated version of an NSMatrix form, where rows slide around as other rows are added or removed), and to build the animation I\'m

I'm trying to create a semi-complex set of view animations (think an animated version of an NSMatrix form, where rows slide around as other rows are added or removed), and to build the animation I'm making a little helper class.

There I have to keep track of the different views, their ordered indices, and few some other values associated with their animations.

To that end, I'm using an NSArray instance to keep track of the ordering (indices) of the views, and I'd like to use an NSDictionary with the views as keys to keep track of the values (the values themselves are in nested dictionaries). I.e. I'd like to be able to do something this, for instance (pseudo code):

NSMutableDictionary* viewValuesDict = [NSDictionary dictionary];

// Loop thru an ordered NSArray
for( (NSView*) view in viewsArray ) {
    // Get some values we'll need later
    NSDictionary* associatedValues = [view getSomeValues];

    // ...and put them into viewValuesDict...
    [viewValuesDict setObject:associatedValues forKey:view];

    // and then things break because the NSView 'view'
    // doesn't support copyWi开发者_运维知识库thZone.... darn
}

Problem is, I of course can't use NSView instances as dictionary keys, because the keys are added using copyWithZone, which NSView does not implement.

So, what's a good way to get a unique key for an NSView instance? I could conceivably use [obj description] since the memory address you get back is a perfect UID, but of course the system has to work with any kind of NSView subclass that might return something else entirely, so that's no good.

Or should I maybe try something else entirely? Is there maybe some alternative to NSDictionary, where keys just aren't copied? Because in this case I really have no need for the keys to ever be copied.


Sometimes there are occasions where you want to use a view (whether NS or UI) as the key in a dictionary. I've come across one such situation. I would've preferred to use objc_setAssociatedObject, but that requires Snow Leopard. Boxing with NSValue will work, but if you need to be doing lots and lots of look ups given a view, the continual boxing and unboxing of pointers may become tedious.

There are two options to creating an NSView => <object> dictionary.

  1. Use NSMapTable
  2. Use CFMutableDictionaryRef

NSMapTable is a class introduced in 10.5 that is very similar to an NSMutableDictionary, except that it has extra abilities that make it work more nicely with garbage collection. In your case, you'll probably want a map table with "weak" keys and "strong" values, but read the documentation for all the fun details.

CFMutableDictionaryRef is the Core Foundation equivalent of an NSDictionary (they are toll-free bridged), but it has some extra creation options. You create one using CFDictionaryCreateMutable(), and that wants two struct parameters. One is a structure that defines the memory management (and other) behavior of how to deal with the keys of the dictionary, and the other is a struct for defining the behavior of the values. You can create a CFMutableDictionaryRef with the options of retaining the keys (instead of copying them) and then retaining the values. Once you've done this, you can cast the CFMutableDictionaryRef to an NSMutableDictionary and use it as you'd expect, just that the keys will be retained instead of copied.


Use NSMapTable instead of NSDictionary (of course you'll have to be sure to manage your object lifetimes carefully if you're not using garbage collection). This article has a good summary of how to use it.


As andyvn22 said, reorganize! But if that isn’t practical:

  • If you’re targeting Snow Leopard, and the associations are likely to persist for the lifetime of the views, use objc_setAssociatedObject().
  • Otherwise, use [NSValue valueWithNonretainedObject:] in preference to -description. (Like it says, it doesn’t retain the object, but your array does.)


Create your dictionaries so that one of their values is the view; then rearrange the code so that you need not look up dictionary based on view, but rather begin either with the dictionaries, or the index (putting the dictionaries into an array), or a unique ID of your own creation (putting the dictionaries into a dictionary; the ID could be as simple as a consecutive number for each new view you begin to keep track of). Unless you're doing something very complicated and dynamic, it should be possible to avoid needing to look up information given only an NSView.

0

精彩评论

暂无评论...
验证码 换一张
取 消