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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.