Andrea
Andrea

Reputation: 26385

Objective-C create a C array property

I'd like to create a property made by an array of CGRect pointers, the number is not defined at the beginning, so I'd like to create a pointer of to a zone o memory that contains the beginning of this array of pointer. It seems quite difficult, I've seen different answer and basing my solution on that.
So far I've writtent that:

@interface ViewController ()
@property (assign) CGRect * rectArray;
@property (strong, nonatomic) NSArray * hotspots;
@end

@implementation ViewController



- (CGRect *) createRectArray {
    int count = _hotspots.count;
    _rectArray = malloc(sizeof(CGRect*)*count);
    for (int i = 0; i<count; i++) {
        CGRect currentFrame = ((UIView*)_hotspots[i]).frame;
        _rectArray[i] = &currentFrame;
    }

    return _rectArray;
}
@end

but the compiler complains telling me that the assignment is not correct.

I'm guessing that probably the correct variable is not a CGRect * rectArray, but a double indirection CGRect ** rectArray.
Is that correct?
[UPDATE]
Actually it doesn't make sense what I want to do... because the property -frame return a copy of CGRect and not a pointer to it, so my idea to have direct and fast access to that is gone.

Upvotes: 1

Views: 175

Answers (2)

Sulthan
Sulthan

Reputation: 130102

The following code accesses the rectArray correctly.

@interface ViewController ()
//array of pointers 
@property (assign) CGRect **rectArray;
@property (strong, nonatomic) NSArray * hotspots;
@end

@implementation ViewController


- (CGRect **) createRectArray {
    int count = _hotspots.count;
    _rectArray = malloc(sizeof(CGRect*)*count);

    for (int i = 0; i<count; i++) {
        //this will never work, the frame returned from UIView is a temporary which will get released!
        CGRect currentFrame = ((UIView*)_hotspots[i]).frame;
        _rectArray[i] = &currentFrame;
    }

    return _rectArray;
}

- (void)dealloc {
   free(_rectArray);
}
@end

However, as I am writing in the comments, this won't work. [UIView frame] returns a C-struct. This behaves the same as primitive variables (NSInteger, long etc.). It gets copied. &currentFrame is a reference to your local stack variable, which will get freed when the code goes outside scope (for iteration ends, method ends). It won't do what you are expecting. Accessing the stored pointers will make your application crash.

Your expected functionality can be accomplished easily by the following two methods

- (void)setFrame:(CGRect)frame forHotspotAtIndex:(NSUinteger)index {
    UIView* hotspot = [self.hotspots objectAtIndex:index];
    hotspot.frame = frame;
}

- (CGRect)frameForHotspotAtIndex:(NSUinteger)index {
    UIView* hotspot = [self.hotspots objectAtIndex:index];
    return hotspot.frame;
}

Upvotes: 1

howanghk
howanghk

Reputation: 3090

If you are allocating an array of CGRects, malloc(sizeof(CGRect*)*count) is wrong as you are trying to allocate an array of pointers to CGRect.
Also when we assign CGRect to the array, we don't need to get its pointer, _rectArray[i] = currentFrame should work just fine.

The following code should work for you:

@interface ViewController ()
@property (assign) CGRect * rectArray;
@property (strong, nonatomic) NSArray * hotspots;
@end

@implementation ViewController

- (CGRect *) createRectArray {
    int count = _hotspots.count;
    _rectArray = malloc(sizeof(CGRect)*count);
    for (int i = 0; i<count; i++) {
        CGRect currentFrame = ((UIView*)[_hotspots objectAtIndex:i]).frame;
        _rectArray[i] = currentFrame;
    }

    return _rectArray;
}
@end

Upvotes: 1

Related Questions