#objective-c #memory-leaks #copy #deep-copy
#objective-c #утечки памяти #Копировать #глубокое копирование
Вопрос:
У меня есть некоторые утечки памяти, и я не совсем уверен, что это вызывает, но после некоторого тестирования кажется, что я облажался при копировании своего объекта, и он не выпущен должным образом. Позвольте мне сначала сказать вам, что я использую ARC, и не так давно я мало что знал о копиях или расширенном управлении памятью, поэтому мне еще многому предстоит научиться. Хорошо, давайте добавим некоторые подробности, у меня есть 2 класса Tree и TreeCell.
Дерево:
@interface Tree : NSObject<NSCopying>
//Here we have 2D array that stores pointers to TreeCell objects
@property (retain,nonatomic)NSMutableArray *tree;
//pointersToTree stores copied pointers from tree,
//it's the same in terms of content but it have different order of rows and columns
@property (retain,nonatomic)NSMutableArray *pointersToTree;
//i don't believe delegate is relevant to my problems (since it's not copied)
@property (weak,nonatomic) id<treeDelagate>delagate;
…
Итак, в short Tree хранятся 2 одинаковых указателя на каждую create TreeCell, по одному в каждом массиве.
TreeCell:
@interface TreeCell : NSObject<NSCopying>
//ancestors and children stores arrays made of 2 NSNubers
@property (retain,nonatomic)NSMutableArray * ancestors;
@property (retain,nonatomic)NSMutableArray * children;
@property (retain,nonatomic)NSNumber* boardY;
@property (retain,nonatomic)NSNumber* boardX;
...// there are some more Integers and Booleans
И вот как выглядят функции копирования, они оба работают, но я не уверен, правильно ли они реализованы, поэтому начинаем с дерева:
-(id) copyWithZone: (NSZone *) zone{
Tree *copy = [[Tree allocWithZone: zone] init];
//this array will become copy of self.tree
NSMutableArray* copyOfTree=[[NSMutableArray alloc]init];
//loop to go thru all stored TreeCell pointers in self.tree
for (NSInteger a=0; a<self.tree.count; a ) {
//adding row
[copyOfTree addObject:[[NSMutableArray alloc]init]];
for (NSInteger b=0; b<[self.tree[a] count]; b ) {
//creating copy of TreeCell and storing pointer to it
[copyOfTree[a] addObject:[((TreeCell*)self.tree[a][b]) copy]];
}
}
copy.tree=copyOfTree;
//by now we copied whole self.tree and since i have function to create pointersToTree out of it I call it below
[copy creatArryOfPointer_Rows:self.pointersToTree.count columns:[self.pointersToTree[0]count]];
return copy;
}
Итак, я пытаюсь получить здесь глубокую копию дерева. Хорошо, вот функция копирования TreeCell:
-(id) copyWithZone: (NSZone *) zone{
//we start here by allocating and setting NSNubers boardY and boardX
TreeCell* copy = [[TreeCell allocWithZone: zone] initWithLayer:self.layer boardX:self.boardX andBoardY:self.boardY];
//after that some integers and booleans are set
copy.helper=self.helper;
copy.inTree=self.inTree;
copy.stableConnected=self.stableConnected;
copy.positon=self.positon;
copy.freeStoreg=self.freeStoreg;
// here we are adding arrays containg 2 NSNumbers
for (int a=0; a<self.ancestors.count; a ) {
[copy addAncestorWithX:self.ancestors[a][0] andY:self.ancestors[a][1]];
}
for (int a=0; a<self.children.count; a ) {
[copy addChildWithX:self.children[a][0] andY:self.children[a][1]];
}
return copy;
}
Чтобы прояснить ситуацию, здесь addAncestor функция addChildren выглядит так же:
-(void) addAncestorWithX:(NSNumber*)ancestorX andY:(NSNumber*)ancestorY{
if ([self.ancestors indexOfObject:[NSArray arrayWithObjects:ancestorX,ancestorY, nil]]==NSIntegerMax) {
[self.ancestors addObject:[NSMutableArray arrayWithObjects:ancestorX,ancestorY, nil]];
}
Наконец, этот фрагмент кода, который создает утечку памяти:
for (NSInteger a=0; a<8000; a ) {
Tree* testTree =[self.startingTree copy];
}
В конце каждого цикла этого цикла должно быть выпущено testTree, после тестирования я на 100% уверен, что для него вызывается dealloc, а также вызывается для каждой ячейки дерева, которая была сохранена в дереве. Но использование памяти постоянно увеличивается. Пожалуйста, скажите мне, где я ошибся. Некоторые параболы идут и говорят, попробуйте сериализовать его, но это не сокращает его для моего.
Комментарии:
1. Чувак, я пытаюсь разобрать, но это ломает мне голову, у вас есть класс под названием tree, который также имеет свойство под названием tree? Итак, в какой-то момент вы получаете строку, которая в основном гласит: «копия объекта дерева классов имеет свойство с именем tree, которое представляет собой массив, которому вы присваиваете массив с именем copyOfTree (но это копия дерева свойств, а не объекта). Это похоже на процедуру «кто первый». 🙂
2. Вы, может быть, называете основной класс таким образом, что это было не самым умным, но вы поняли, что это именно то, что происходит в коде. Класс Tree — это все о его дереве свойств, которое является 2D-массивом, поэтому, когда я хочу копию класса, я не буду копировать этот массив, поэтому копируйте каждую ячейку дерева, которая находится в этом массиве (ну, внутри на самом деле есть указатели на них). Я полагаю, что моя проблема заключается где-то в функции copyWithZone для TreeCell, завтра я проведу еще несколько тестов. Вероятно, это NSNumbers, которые всегда являются проклятием моего существования.
3. Я почти уверен, что у вас есть цикл сохранения, может быть, десятки. Я не думаю, что большая часть копирования, которое вы делаете, на самом деле необходима, поскольку в конечном итоге вы помещаете все одинаковые указатели во все. Но пока вы понимаете, что такое цикл сохранения, вы с этим разберетесь.
4. Да, я тоже так считаю. На самом деле тот факт, что для TreeCell вызываются deallocs, будет означать, что больше нет ссылок на этот объект и его родительский элемент, который является деревом, поэтому внутри самой TreeCell должны быть какие-то оставшиеся объекты, а их не так много. Я надеюсь, что это все. Хорошо, поскольку сейчас 2 часа ночи, я назову это на сегодня. Спасибо!
Ответ №1:
Я думаю, что вы делаете какие-то сумасшедшие вещи с копированием, но я не могу точно сказать, какова ваша цель при копировании, поскольку она относится к фактически объектам, хранящимся в массиве, поэтому я могу ошибаться. Без написания множества возможных ответов и комментариев. Сначала посмотрите, решает ли это ваши проблемы:
NSMutableArray *someArray = [NSMutableArray array];
NSMutableArray *aCopyOfSomeArray = [NSMutableArray arrayWithArray:someArray];
Комментарии:
1. Сначала спасибо за усилия по прохождению через этот молох, но это просто создаст второй массив с теми же указателями, поэтому они будут указывать на те же объекты, мне нужно, чтобы они указывали на фактически новые объекты, которые будут идентичны старым.
Ответ №2:
И вот оно у меня есть! Проблема была внутри моей функции для добавления дочерних элементов и предков.
[self.ancestors addObject:[NSMutableArray arrayWithObjects:ancestorX,ancestorY, nil]];
Это, безусловно, добавило массив, который я хотел, но он не выделил для него место!
Итак, я изменил этот код:
for (int a=0; a<self.ancestors.count; a ) {
[copy addAncestorWithX:self.ancestors[a][0] andY:self.ancestors[a][1]];
}
for (int a=0; a<self.children.count; a ) {
[copy addChildWithX:self.children[a][0] andY:self.children[a][1]];
}
В это:
for (int a=0; a<self.ancestors.count; a ) {
[copy.ancestors addObject:[[NSMutableArray alloc]init]];
[copy.ancestors[a] addObject:self.ancestors[a][0]];
[copy.ancestors[a] addObject:self.ancestors[a][1]];
}
for (int a=0; a<self.children.count; a ) {
[copy.children addObject:[[NSMutableArray alloc]init]];
[copy.children[a] addObject:self.children[a][0]];
[copy.children[a] addObject:self.children[a][1]];
}
Итак, ребята, мой совет: когда вам нужно глубокое копирование, убедитесь, что вы выделили новое пространство для всех ваших массивов, и убедитесь, что объекты не указывают наружу, когда они не должны.