Хранение указателей на структуры в NSMutableArray

#ios #objective-c #pointers

#iOS #objective-c #указатели

Вопрос:

Задача: я хочу создать a NSMutableArray , который содержал бы указатели на CGPoint структуры, а затем использовал бы эти указатели в других объектах (созданных на заказ, унаследованных от NSObject ) и массивах, так что, когда я изменяю фактические значения за указателями в NSMutableArray , это было бы видно отовсюду. Мне не нравится идея инкапсулировать его, NSValue так как это нарушило бы функциональность так, как я хочу.

Теперь немного кода:

 // 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)amp;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
 

Проблема:
Я думал, что этот код правильный, со всеми мостами и прочим, но он вылетает при вставке в rawPoints, даже не доходя до конца. Слишком грустно.

Вопрос: Может ли кто-нибудь помочь мне понять, что я сделал не так, и помочь мне исправить это, чтобы оно работало так, как я описал, возможно, используя другие объекты или методы?

Спасибо!

Комментарии:

1. мост не преобразуется волшебным CGPoint * образом в действительный объект ObjC. вы пытались обмануть компилятор, чтобы он скомпилировал ваш код. но это не заставит ваш код работать.

2. Поскольку все «допустимые объекты ObjC» являются указателями, я подумал, что это сработает. Я думаю, так мы учимся 🙂

Ответ №1:

У вас есть гораздо более фундаментальная проблема, чем хранение указателей на структуры…

Структура — это тип значения и внутри функции / метода, что означает, что она выделяется автоматически с ограниченным сроком службы. В вашем коде:

 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)amp;p]; // *** crashes here
    }
}
 

Время жизни p — от момента его создания до конца текущей (внутренней) итерации цикла. То amp;p , что вы пытаетесь сохранить, недействительно сразу после того, как вы (в данном случае не удалось) сохраните его.

Вам либо нужно сохранить свои точки как значения, либо, если вы хотите их изменить, сохранить их в динамической памяти. Существуют различные способы сделать это, но самым простым для вас может быть просто создание простого класса-оболочки, который содержит CGPoint :

 @interface CGPointWrapper

@property CGPoint point;

@end

@implementation CGPointWrapper
// nothing to do
@end
 

Примечание: если вы создаете CGPoint свойство, как указано выше, установка элементов структуры с использованием этого свойства не изменяет значение, хранящееся в классе, из-за семантики значений. Однако вы можете присвоить всему значению struct новое CGPoint значение. Если вы хотите задать элементы структуры, вам нужно будет добавить методы для этого.

HTH

Комментарии:

1. Это звучит очень многообещающе! Собираюсь попробовать это как можно скорее, спасибо за дополнительную информацию, объяснение и пример кода, я ценю это! 🙂

Ответ №2:

Вам не разрешается хранить указатели, не являющиеся объектами, в обычных классах коллекции. Согласно документам, существуют специальные классы коллекций ( NSPointerArray , NSMapTable , и NSHashTable ) для обработки коллекций произвольных указателей.

Комментарии:

1. Существует также объект — я забыл имя — для хранения значений, не являющихся объектами.

2. @HotLicks: Да, NSValue (который был специально упомянут как нежелательный в вопросе) можно использовать для переноса CGPoint , и я думаю, что практически любой произвольный указатель, чтобы поместить его в один из обычных классов коллекции. (Хотя его проще использовать NSValue для переноса CGPoint и т.п. в OSX, чем в iOS, потому что функциональность, предоставляемая NSValue лучше …)

3. Это может помочь с некоторой частью моей проблемы, но, как заявил @CRD в своем ответе, время жизни структур — это реальная проблема, которую необходимо решить, и я согласен с этим после рассмотрения. Но все же спасибо за информацию! Я уверен, что очень скоро им воспользуюсь 🙂