Заброшенный вопрос памяти - PullRequest
1 голос
/ 17 марта 2011

Не могли бы вы мне помочь, пожалуйста, мое приложение почти завершено, я сейчас нахожусь в процессе его оптимизации, поэтому я использую инструменты Распределения инструментов и у меня проблема с контроллером вида, но я не могу понять почему память увеличивается с каждым разом, когда я перехожу с основного представления на подробный ViewController.

Вот часть кода, которая, кажется, является проблемой:

  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

// Create and push a detail view controller.

    self.entriesDetailedViewController = [[EntriesDetailedViewController alloc]init];

Entry *selectedEntry = (Entry *)[[self fetchedResultsController] objectAtIndexPath:indexPath];

self.entriesDetailedViewController.entry = selectedEntry;

[self.navigationController pushViewController:self.entriesDetailedViewController animated:YES];
[self.entriesDetailedViewController release];
}

Вот код для подробного ViewController.h:

  #import <UIKit/UIKit.h>


  @class Entry;

 @interface EntriesDetailedViewController : UIViewController <UITextViewDelegate> {

//IBOutlet UIButton *createEntryButton;
IBOutlet UITextField *entryTextField1;
IBOutlet UITextView *entryTextField2;
IBOutlet UIBarButtonItem *textbodyBarButton;
IBOutlet UIBarButtonItem * catLabel;
IBOutlet UINavigationBar *entryNameToolBar;
IBOutlet UINavigationBar *textBodyToolBar;
IBOutlet UIImageView *reviewCheck;
IBOutlet UIImageView *textBackground;
IBOutlet UIBarButtonItem *reviewButton;
BOOL isChecked;

NSManagedObjectContext *managedObjectContext;


Entry *entry;

    }


 @property (nonatomic,retain) IBOutlet UITextField *entryTextField1;
 @property (nonatomic,retain) IBOutlet UITextView *entryTextField2;
 @property (nonatomic,retain) IBOutlet UIBarButtonItem *textbodyBarButton;
 @property (nonatomic,retain) IBOutlet UIBarButtonItem *catLabel;
 @property (nonatomic,retain) IBOutlet UINavigationBar *entryNameToolBar;
 @property (nonatomic,retain) IBOutlet UINavigationBar *textBodyToolBar;
 @property (nonatomic,retain) IBOutlet UIImageView *reviewCheck;
 @property (nonatomic,retain) IBOutlet UIBarButtonItem *reviewButton;
 @property BOOL isChecked;
 @property (nonatomic,retain) IBOutlet UIImageView *textBackground;

 @property (nonatomic,retain) NSManagedObjectContext *managedObjectContext;
 @property (nonatomic, retain) Entry *entry;


 - (void)setUpUndoManager;
 - (void)cleanUpUndoManager;
 - (void)textViewDidBeginEditing:(UITextView *)entryTextField2;
 - (void)textViewDidEndEditing:(UITextView  *)entryTextField2;
 - (void)saveContext;



 - (IBAction)dismisskeyboard;
 - (IBAction)dismissKeyboardfromTextView;
 - (IBAction) selectReview;


 @end

а это этот подробный ViewController.m:

  #import "EntriesDetailedViewController.h"
  #import "Entry.h"
  #import "TheLearningMachineAppDelegate.h"


  @implementation EntriesDetailedViewController

  @synthesize entryTextField1,entryTextField2,textbodyBarButton,managedObjectContext,catLabel, entryNameToolBar,textBodyToolBar, reviewCheck,reviewButton,isChecked,textBackground, entry, undoManager;


  #pragma mark -
  #pragma mark View lifecycle


  - (void)viewWillAppear:(BOOL)animated {

  }

  - (void)viewDidLoad {
      [super viewDidLoad];

  // Configure the title, title bar, and table view.

      self.title = @"Consultation";

    UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(save:)]; 
self.navigationItem.rightBarButtonItem = rightButton; 
[rightButton release];

[self setUpUndoManager];

self.entryTextField1.text = self.entry.entryname;
self.entryTextField2.font = [UIFont fontWithName:@"Helvetica" size:17.0];
self.entryTextField2.text = self.entry.textbody;
self.catLabel.title = self.entry.category;
[self.entryTextField2 setFrame:CGRectMake(24, 56, 273, 140)];

self.textBackground.image = [UIImage imageNamed:@"alert_background.png"];
[self.textBackground setFrame:CGRectMake(0,46,312,140)];



  //Initializing a kind of checkBox button

if ([self.entry.active boolValue] == YES) {

    self.reviewCheck.image = [UIImage imageNamed:@"checkedwhitesquare.png"];

    self.isChecked = YES;
}

else {

    self.reviewCheck.image = [UIImage imageNamed:@"UncheckedWhiteSquare.png"];

    self.isChecked = NO;

}

  }


  - (IBAction) selectReview {

      if (isChecked==NO){
        self.reviewCheck.image = [UIImage imageNamed:@"checkedwhitesquare.png"];
    self.isChecked = YES;
    [self.entry setValue:[NSNumber numberWithBool:YES] forKey:@"active"];
    [self performSelector: @selector(save:)];

}
else {

    self.reviewCheck.image = [UIImage imageNamed:@"UncheckedWhiteSquare.png"];

    self.isChecked = NO;
    [self.entry setValue:[NSNumber numberWithBool:YES] forKey:@"active"];
    [self performSelector: @selector(save:)];

}

  }



  - (void)textViewDidBeginEditing:(UITextView  *)entryTextField2{
[self.navigationController setNavigationBarHidden:YES animated:YES];
self.entryNameToolBar.hidden =YES; 
self.textBodyToolBar.hidden =NO;
self.textbodyBarButton.style =UIBarButtonItemStyleBordered;
self.textbodyBarButton.title =@"Terminer la saisie";
[self.entryTextField2 setFrame:CGRectMake(24, 50, 273, 140)];
[self.textBackground setFrame:CGRectMake(0,46,312,140)];
  }

  - (IBAction)textViewDidEndEditing: (UITextView  *)entryTextField2{
      [self.navigationController setNavigationBarHidden:NO animated:YES];
      self.entryNameToolBar.hidden =NO;
      self.textBodyToolBar.hidden =YES;
      [self.entryTextField2 setFrame:CGRectMake(24, 50, 273, 140)];
      [self.textBackground setFrame:CGRectMake(0,46,312,140)];
      self.textbodyBarButton.style =UIBarButtonItemStyleDone;
      self.textbodyBarButton.title =@"Corps de texte";  

  }

  - (IBAction)dismisskeyboard{

[self.entryTextField1 resignFirstResponder];
  }

  - (IBAction)dismissKeyboardfromTextView{

[self.entryTextField2 resignFirstResponder];

  }

  - (void)saveContext {

      NSError *error = nil;
      if (self.managedObjectContext != nil) {
          if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Erreur" 
        message:@"blabla" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];


        abort();

          } 
      }
  }  


  - (IBAction)save:(id)sender {

      // if there's text in textfield1 and textfield2 and a category has been set 
      if (([self.entryTextField1.text length]!= 0) && ([self.entryTextField2.text length]!= 0) && ([self.catLabel.title length]!= 0)){ 

    [self.entry setValue:self.entryTextField1.text forKey:@"entryname"];
    [self.entry setValue:self.entryTextField2.text forKey:@"textbody"];
    [self.entry setValue:self.catLabel.title forKey:@"category"];

    if (self.isChecked == YES) {
        [self.entry setValue:[NSNumber numberWithBool:YES]forKey:@"active"];
    }
    else {

        [self.entry setValue:[NSNumber numberWithBool:NO] forKey:@"active"];
    }

    [self.entry setValue:[NSNumber numberWithBool:NO] forKey:@"editable"];

    //save
    NSError *error;
    [self.managedObjectContext save:&error];
    [self saveContext];

    //Return to mainview
    [self.navigationController popViewControllerAnimated:YES];
    [self.entry release];
    //self.entry =nil;
}

else {

    if([self.entryTextField1.text length] ==0){

        UIAlertView *alert =[[UIAlertView alloc] 
                             initWithTitle:@"Oooops..." 
                             message:@"Your entry has no name" 
                             delegate:nil 
                             cancelButtonTitle: @"ok" 
                             otherButtonTitles:nil];
        [alert show];
        [alert release];

    }
    else {

        if ([self.entryTextField2.text length]==0){

            UIAlertView *alert =[[UIAlertView alloc] initWithTitle:@"Oooops..." message:@"Your list is empty" delegate:nil cancelButtonTitle: @"ok" otherButtonTitles:nil];
            [alert show];
            [alert release];

        }
        else {

            if ([self.catLabel.title length]==0){

                UIAlertView *alert =[[UIAlertView alloc] initWithTitle:@"Oooops..." message:@"You need to choose a category for this list first." delegate:nil cancelButtonTitle: @"ok" otherButtonTitles:nil];
                [alert show];
                [alert release];

                  }
              }

          }
      }
   }


  - (void)setEditing {
  //    [super setEditing:editing animated:animated];
  }




  #pragma mark -
  #pragma mark Undo support

  - (void)setUpUndoManager {

    if (self.entry.managedObjectContext.undoManager == nil) {

    NSUndoManager *undoMgr = [[NSUndoManager alloc] init];
    [undoMgr setLevelsOfUndo:1];
    self.entry.managedObjectContext.undoManager = undoMgr;
    [undoMgr release];


    }

    // Register as an observer of the entry's context's undo manager.
    NSUndoManager *entryUndoManager = self.entry.managedObjectContext.undoManager;
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
    [dnc addObserver:self selector:@selector(undoManagerDidUndo:) name:NSUndoManagerDidUndoChangeNotification object:entryUndoManager];
    [dnc addObserver:self selector:@selector(undoManagerDidRedo:) name:NSUndoManagerDidRedoChangeNotification object:entryUndoManager];


  }


  - (void)cleanUpUndoManager {

      // Remove self as an observer.
      [[NSNotificationCenter defaultCenter] removeObserver:self];

      if (self.entry.managedObjectContext.undoManager == undoManager) {
          self.entry.managedObjectContext.undoManager = nil;
          self.undoManager = nil;
      }       
  }


  - (NSUndoManager *)undoManager {
      return self.entry.managedObjectContext.undoManager;
  }


  - (void)undoManagerDidUndo:(NSNotification *)notification {

  }


  - (void)undoManagerDidRedo:(NSNotification *)notification {

  }

  - (BOOL)canBecomeFirstResponder {
      return YES;
  }


  - (void)viewDidAppear:(BOOL)animated {
      [super viewDidAppear:animated];
      [self becomeFirstResponder];
  }


  - (void)viewWillDisappear:(BOOL)animated {
      [super viewWillDisappear:animated];
      [self resignFirstResponder];
  }

- (void)viewDidUnload {

// Release any properties that are loaded in viewDidLoad or can be recreated lazily.


self.entryTextField1 =nil;
self.entryTextField2 = nil;
self.catLabel = nil;
self.entryNameToolBar = nil;
self.textBodyToolBar = nil;
self.reviewCheck = nil;
self.textBackground = nil;
self.reviewButton = nil;
self.entry = nil;
self.navigationItem.rightBarButtonItem = nil;
[self cleanUpUndoManager];
self.entry.managedObjectContext.undoManager = nil;


}

  - (void)dealloc {

[entryTextField1 release], entryTextField1 = nil;
[entryTextField2 release], entryTextField2 = nil;
[catLabel release], catLabel = nil;
[entryNameToolBar release], entryNameToolBar = nil;
[textBodyToolBar release], textBodyToolBar = nil;
[reviewCheck release], reviewCheck = nil;
[textBackground release], textBackground = nil;
[reviewButton release], reviewButton = nil;
[self cleanUpUndoManager];
[entry.managedObjectContext.undoManager release],  
     entry.managedObjectContext.undoManager = nil;
[entry release],entry = nil;
[managedObjectContext release];


[super dealloc];
}

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

Как вы, ребята, предложили, я сделал следующие модификации:

Я также изменил части кода viewDidUnload и Dealloc, которые теперь выглядят так:

Я не совсем понимаю концепцию release + nil и разницу между вызовом [self.object release] и [object release] в dealloc и при вызове self.object = nil в viewDidUnload.

Ответы [ 4 ]

1 голос
/ 17 марта 2011

Вы должны ожидать, что использование вашей памяти будет увеличиваться при каждом выделении нового EntriesDetailedViewController.Я полагаю, вы имеете в виду, что ваша память не возвращается, когда вы ее отпускаете?Вы, вероятно, неправильно выпускаете что-то в -[EntriesDetailedViewController dealloc].

. Обратите внимание, что вместо того, чтобы генерировать новый EntriesDetailedViewController каждый раз, вероятно, здесь лучше просто создать его в первый раз, когда вам это нужно, и простоперенастроить его на setEntry:.Вы уже настроили ivar для удержания контроллера вида;может также использовать это.

0 голосов
/ 20 марта 2011

Эй, эй, ты знаешь что парни? Я только что узнал !!!!!!!! Как глупо я ... Если вы внимательно посмотрите в файл recordsDetailedViewController.h, вы увидите, что есть textbodyBarButton, который объявлен ... Ну, он не был выпущен, я забыл об этом ...

Прошу прощения за то, что заставил вас терять время.

Я только что добавил:

    self.textbodyBarButton = nil;
[textbodyBarButton release];

И теперь я в порядке, когда я возвращаюсь к rootViewController, вся память освобождается.

Так что, если у вас, ребята, одна и та же проблема, однажды, это может быть глупо. Просто проверьте дважды, что вы объявили в своем .h файле.

Ух ты, а на это потратил 3 дня ...

Большое спасибо всем вам и еще раз спасибо за ваше терпение.

0 голосов
/ 17 марта 2011

Вы должны использовать эту форму в dealloc:

[entryTextField1 release], entryTextField1 = nil;

Вы должны использовать эту форму для установки (например, в viewDidUnload):

self.entryTextField1 = nil;

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

, как только все это исправлено, затем перезапустите приложение.(Я предполагаю, что это не будет 100% охват)

также убедитесь, что вы используете контроль версий.вы обнаружите, что выслеживаете много проблем - пока все они не улажены, вы должны ожидать новых проблем / сбоев по пути.

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

0 голосов
/ 17 марта 2011

Причина не очевидна из кода, который вы опубликовали, но Instruments показывает вам, где происходило каждое выделение, поэтому его не должно быть сложно отследить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...