0

Task: I want to create a NSMutableArray which would hold pointers to CGPoint structures, and then use these pointers in other objects (custom-made, inherited from NSObject) and arrays, so that when I change actual values behind the pointers in the NSMutableArray, it would be seen from everywhere. I don't like the idea of encapsulating it in NSValue since that would break the functionality as I want it.

Some code now:

// Triangle.h

@interface Triangle : NSObject
{
    CGPoint *p1;
    CGPoint *p2;
    CGPoint *p3;
}

@property (nonatomic) CGPoint *p1;
@property (nonatomic) CGPoint *p2;
@property (nonatomic) CGPoint *p3;

@end
// @synthesize in Triangle.m for p1, p2, p3


// somewhere in MyCustomView.m

CGFloat *MRatio = 3.0f; // some values
CGFloat *NRatio = 5.0f; // doesn't matter

rawPoints = [[NSMutableArray alloc] init];

for (NSInteger i = 0; i < N; i++)
{
    for (NSInteger j = 0; j < M; j++)
    {
        CGPoint p = CGPointMake(j * MRatio, i * NRatio);
        [rawPoints addObject:(__bridge id)&p]; // *** crashes here
    }
}


Triangle *t = [[Triangle alloc] init];
t.p1 = (__bridge CGPoint *)([rawPoints objectAtIndex:0]);

NSLog(@"%@", NSStringFromCGPoint(*t.p1)); // original value

CGPoint *pp1 = (__bridge CGPoint *)([rawPoints objectAtIndex:0]);
*pp1 = CGPointMake(-1.0f, -1.0f);

NSLog(@"%@", NSStringFromCGPoint(*t.p1)); // changed value

Problem: I thought the code this way is correct, with all the bridges and stuff, but it crashes on the inserting to rawPoints, not even getting to the end. Too sad.

Question: Can someone help me understand what I did wrong, and help me make it right so it works in the way I described, perhaps using a different objects or methods?

Thanks!

2
  • bridge doesn't magically convert CGPoint * to a valid ObjC object. you were trying to fool the compiler so it compile your code. but it won't make your code work. Commented Jun 23, 2014 at 22:29
  • Since all "valid ObjC objects" are pointers, I thought that'd do the trick. That's how we learn, I guess :) Commented Jun 24, 2014 at 6:30

2 Answers 2

5

You have a far more fundamental problem than storing pointers to structs...

A struct is a value type and within a function/method that means it is allocated automatically with a limited lifetime. In your code:

for (NSInteger i = 0; i < N; i++)
{
    for (NSInteger j = 0; j < M; j++)
    {
        CGPoint p = CGPointMake(j * MRatio, i * NRatio);
        [rawPoints addObject:(__bridge id)&p]; // *** crashes here
    }
}

The lifetime of p is from its point of creation to the end of the current (inner) loop iteration. The &p you are trying to store is invalid immediately after you (fail in this case) to store it.

You either need to store your points as values, or if you want to mutate them store them in dynamic memory. There are various ways to do this but the simplest for you might be to just create a simple wrapper class which contains the CGPoint:

@interface CGPointWrapper

@property CGPoint point;

@end

@implementation CGPointWrapper
// nothing to do
@end

Note: if you create a CGPoint property, as above, setting elements of the structure using this property does not alter the value stored in the class - due to value semantics. However you can set the whole struct value to a new CGPoint value. If you wish to set elements of the structure you will need to add methods to do that.

HTH

Sign up to request clarification or add additional context in comments.

1 Comment

This sounds very promising! Going to try it asap, thanks for the additional info, explanation and code example, I appreciate it! :)
1

You aren't allowed to store non-object pointers in the usual collection classes. According to the docs, there are specialty collection classes (NSPointerArray, NSMapTable, and NSHashTable) to handle collections of arbitrary pointers.

4 Comments

There is also an object -- I forget the name -- for storing non-object values.
@HotLicks: Yep, NSValue (which was specifically mentioned as not being desired in the question) can be used to wrap CGPoint and I think pretty much any arbitrary pointer in order to put it into one of the usual collection classes. (Although it's easier to use NSValue to wrap CGPoint and the like on OSX than on iOS because the functionality provided by NSValue is better...)
That might help with some part of my problem, but as @CRD stated in his answer, the lifetime of the structures is the real problem needed to be solved, and I agree to that after consideration. Thanks for the info though! I'm sure I'll use it very soon :)
This is the correct answer, although it would be more generous to also write a sample few lines to demonstrate the use of NSHashTable for storing those CGPoint structs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.