Re: Help with NSPointerArray and NSMapTable
Christiaan Hofman <[email protected]>
| Newsgroups | gmane.comp.macosx.devel |
|---|---|
| Message-ID | <[email protected]> |
On Sep 23, 2009, at 0:58, Jonathan Dann wrote:
> On 21 Sep 2009, at 20:22, Christiaan Hofman wrote:
>
>> I am trying to create arrays and dictionaries containing non-object
>> types like NSInteger, CGFloat, and structs like NSRect. This should
>> be possible using NSPointerArray/NSMapTable and appropriate pointer
>> functions. But I am very much confused about which pointer function
>> options to use and how to add/remove values.
> [snip]
>
> Hi Christiaan,
>
> You're along the right lines but you need to also set the
> sizeFunction on the NSPointerFunctions. This is a pointer to a
> function that returns the size of type you'll be using in the array.
> The collections (presumably) use the size function in the malloc()
> call when they take ownership of the value.
Right, that's basically what I proposed as well. So I also need to use
this for simple types like CGFloat that are not pointer-sized?
> I have some categories on NSPointerFunctions and NSPointerArray for
> the common struct types:
>
> @implementation NSPointerFunctions (ESAdditions)
>
> static NSUInteger _ESPointerArrayCGRectStructSize(const void *item)
> {
> return sizeof(CGRect);
> }
>
> static NSUInteger _ESPointerArrayCGPointStructSize(const void *item)
> {
> return sizeof(CGPoint);
> }
>
> static NSUInteger _ESPointerArrayNSRangeStructSize(const void *item)
> {
> return sizeof(NSRange);
> }
>
> static NSUInteger _ESPointerArrayCGSizeStructSize(const void *item)
> {
> return sizeof(CGSize);
> }
>
>
> + (NSPointerFunctions *)pointerFunctionsForNSRange;
> {
> NSPointerFunctions *aPointerFunctions = [NSPointerFunctions
> pointerFunctionsWithOptions:(NSPointerFunctionsStructPersonality|
> NSPointerFunctionsMallocMemory|NSPointerFunctionsCopyIn)];
> [aPointerFunctions
> setSizeFunction:&_ESPointerArrayNSRangeStructSize];
> return aPointerFunctions;
> }
>
> + (NSPointerFunctions *)pointerFunctionsForCGRect;
> {
> NSPointerFunctions *aPointerFunctions = [NSPointerFunctions
> pointerFunctionsWithOptions:(NSPointerFunctionsStructPersonality|
> NSPointerFunctionsMallocMemory|NSPointerFunctionsCopyIn)];
> [aPointerFunctions setSizeFunction:&_ESPointerArrayCGRectStructSize];
> return aPointerFunctions;
> }
>
> + (NSPointerFunctions *)pointerFunctionsForCGPoint;
> {
> NSPointerFunctions *aPointerFunctions = [NSPointerFunctions
> pointerFunctionsWithOptions:(NSPointerFunctionsStructPersonality|
> NSPointerFunctionsMallocMemory|NSPointerFunctionsCopyIn)];
> [aPointerFunctions
> setSizeFunction:&_ESPointerArrayCGPointStructSize];
> return aPointerFunctions;
> }
>
> + (NSPointerFunctions *)pointerFunctionsForCGSize;
> {
> NSPointerFunctions *aPointerFunctions = [NSPointerFunctions
> pointerFunctionsWithOptions:(NSPointerFunctionsStructPersonality|
> NSPointerFunctionsMallocMemory|NSPointerFunctionsCopyIn)];
> [aPointerFunctions setSizeFunction:&_ESPointerArrayCGSizeStructSize];
> return aPointerFunctions;
> }
> @end
>
> @implementation NSPointerArray (ESExtensions)
>
> + (id)rangePointerArray;
> {
> return [[[self alloc] initWithPointerFunctions:[NSPointerFunctions
> pointerFunctionsForNSRange]] autorelease];
> }
>
> + (id)rectPointerArray;
> {
> return [[[self alloc] initWithPointerFunctions:[NSPointerFunctions
> pointerFunctionsForCGRect]] autorelease];
> }
>
> + (id)pointPointerArray;
> {
> return [[[self alloc] initWithPointerFunctions:[NSPointerFunctions
> pointerFunctionsForCGPoint]] autorelease];
> }
>
> + (id)sizePointerArray;
> {
> return [[[self alloc] initWithPointerFunctions:[NSPointerFunctions
> pointerFunctionsForCGSize]] autorelease];
> }
>
> @end
>
> If you add NS_BUILD_32_LIKE_64 to the preprocessor macros in Xcode,
> you can use CG/NS Rect, Point and Size interchangeably.
>
I prefer to use NSRectFromCGRect etc., that just always does the right
thing.
> Note that +[NSPointerArray pointerArrayWithPointerFunctions:] seems
> to crash on 10.5.x, hence the -initWith... calls.
>
> In you client code, do something like
>
> NSRect aRect = NSZeroRect;
> NSPointerArray *aRectArray = [NSPointerArray rectPointerArray];
> [aRectArray addPointer:&aRect];
>
> // some time later ......
>
> NSRect aRect = *(NSRectPointer)[aRectArray pointerAtIndex:index]
>
> Hope this helps,
>
> Jonathan
Nice samples, that surely helps. Thanks. I just find it confusing that
for NSInteger it works differently. Though I guess I could do the same.
Christiaan