Невозможно остановить утечку памяти

#objective-c #memory-management #memory-leaks

#objective-c #управление памятью #утечки памяти

Вопрос:

Я пытаюсь научить себя Objective-c. У меня есть много книг, все из которых я прочитал, чтобы попытаться решить мою проблему. Я рисую себе карту со следующим кодом.

 -(void)drawMap
{
    for (NSInteger tempY=character.locationY-5;tempY<character.locationY 6;tempY  )
    {
        for (NSInteger tempX=character.locationX-4;tempX<character.locationX 5;tempX  )
        {
            MapTile *a = [[MapTile alloc] initWithFrame:CGRectMake
                            (((tempX-(character.locationX-3)) * 44) 6,
                            ((tempY-(character.locationY-5)) * 44)-12,0,0)
                            :[map getTilePic:tempY:tempX]];
            [self.view addSubview:a];
        }
    }
    CharacterTile *a = [[CharacterTile alloc] initWithFrame:CGRectMake(138,206,0,0)]; 
    [self.view addSubview:a];
}
  

И мой MapTile выглядит следующим образом —

 -(id)initWithFrame:(CGRect)frame :(NSInteger)pictureNumber
{
    if (!dungeonLoaded)
    {
        UIImage *tempImage;
        for (NSInteger count=0;count<54;count  )
        {
            NSString *temp = [NSString alloc];
            temp = [NSString stringWithFormat:@"%i.png", count];
            tempImage = [UIImage imageNamed:temp];
            loadedImage[count] = tempImage;
        }
        dungeonLoaded = YES;
    }
    CGRect rect = CGRectMake(frame.origin.x,frame.origin.y,
                             loadedImage[pictureNumber].size.width,
                             loadedImage[pictureNumber].size.height);
    self = [super initWithFrame:rect];
    image = [loadedImage[pictureNumber] retain];
    self.opaque = NO;
    self.backgroundColor = [UIColor clearColor];
    return self;
}
  

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

Изначально изображения maptile загружались при каждом перемещении, и я подумал, что это может быть проблемой, поэтому изменил ее, как вы можете видеть, чтобы загружать изображения только один раз и повторно использовать их. Я попытался использовать imagecache из книги «Начало разработки игр для Iphone» и очищать кэш в начале каждого метода drawmap. Я попытался дополнить пул автозапуска и загрузить плитки с тегом автозапуска. Я попытался освободить фрагменты по мере их отрисовки, но, как и следовало ожидать, это уничтожило изображение на экране, и поэтому карта не была видна.

Я не ленивый и много раз пытался заставить это прекратить замедление, но, к сожалению, на данный момент это выходит за рамки моих навыков кодирования.

Любая помощь была бы высоко оценена.

Заранее спасибо.

Адам

Ответ №1:

Существует ряд проблем:

  1. Вы alloc создаете несколько MapTile экземпляров каждый раз, когда рисуете карту, но никогда не выпускаете их.

  2. Вы alloc создаете CharacterTile экземпляр каждый раз, когда рисуете карту, и никогда не выпускаете его.

  3. Ваш MapTile конструктор выделяет NSString экземпляр, который никогда не будет выпущен.

  4. Ваш MapTile конструктор вызывает retain loadedImage[pictureNumber] , но соответствия нет release .

  5. Вы добавляете экземпляры MapTile и CharacterTile в представление повторно, но ваш код не удаляет предыдущие экземпляры из представления.

Итак, 1-4 — это плохо, но я бы поспорил, что это # 5, который снижает вашу производительность. Вы накапливаете все больше и больше вложенных представлений каждый раз, когда обновляете карту, и никогда не удаляете свои старые фрагменты из представления. Ваш код накладывает новые плитки поверх старых, и чем больше становится куча, тем медленнее будет работать ваше приложение.

В любом случае, это должно устранить проблемы 1-3:

 -(void)drawMap
{
    for (NSInteger tempY=character.locationY-5;tempY<character.locationY 6;tempY  )
    {
        for (NSInteger tempX=character.locationX-4;tempX<character.locationX 5;tempX  )
        {
            MapTile *a = [[MapTile alloc] initWithFrame:CGRectMake
                            (((tempX-(character.locationX-3)) * 44) 6,
                            ((tempY-(character.locationY-5)) * 44)-12,0,0)
                            :[map getTilePic:tempY:tempX]];
            [self.view addSubview:a];
            [a release];
        }
    }
    CharacterTile *a = [[CharacterTile alloc] initWithFrame:CGRectMake(138,206,0,0)]; 
    [self.view addSubview:a];
    [a release];
}

-(id)initWithFrame:(CGRect)frame :(NSInteger)pictureNumber
{
    if (!dungeonLoaded)
    {
        UIImage *tempImage;
        for (NSInteger count=0;count<54;count  )
        {
            NSString* temp = [NSString stringWithFormat:@"%i.png", count];
            tempImage = [UIImage imageNamed:temp];
            loadedImage[count] = tempImage;
        }
        dungeonLoaded = YES;
    }
    CGRect rect = CGRectMake(frame.origin.x,frame.origin.y,
                             loadedImage[pictureNumber].size.width,
                             loadedImage[pictureNumber].size.height);
    self = [super initWithFrame:rect];
    image = [loadedImage[pictureNumber] retain];  //FIXME:  you need to release this somewhere
    self.opaque = NO;
    self.backgroundColor = [UIColor clearColor];
    return self;
}
  

С проблемами 4-5 вам придется разобраться самостоятельно. Но если вы просто обновите drawMap , чтобы удалить все подвиды перед добавлением любых новых, я думаю, вы пройдете большую часть пути.