[英]Abandoned memory issue
您能幫我個忙嗎,我的應用程序快要完成了,我現在正在對其進行優化,因此我正在使用儀器分配工具,但視圖控制器存在問題,但我不知道為什么要使用內存每當我從主視圖轉到detailedViewController時,它都會增加。
這是似乎是問題的代碼部分:
- (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];
}
這是detailedViewController.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
這是detailedViewController.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的概念,也不了解在dealloc中調用[self.object release]和[object release]以及在viewDidUnload中調用self.object = nil之間的區別。
您應該期望每次分配新的EntriesDetailedViewController
時,內存使用量都會增加。 我以為您的意思是釋放記憶時記憶不會消失嗎? 您可能沒有在-[EntriesDetailedViewController dealloc]
正確釋放某些內容。
請注意, EntriesDetailedViewController
每次都生成一個新的EntriesDetailedViewController
,不如在您第一次需要時創建一個,並繼續使用setEntry:
對其進行重新配置,可能會更好。 您已經設置了ivar來容納視圖控制器。 不妨利用它。
從您發布的代碼來看,原因並不明顯,但是Instruments會向您顯示每次分配的發生位置,因此跟蹤它並不難。
您應該在dealloc中使用以下形式:
[entryTextField1 release], entryTextField1 = nil;
您應該使用此表單進行設置(例如,在viewDidUnload
):
self.entryTextField1 = nil;
運行靜態分析應該會遇到更多問題。 修復它們。
糾正所有問題后,請重新運行該應用程序。 (我假設不會100%覆蓋)
另外,請確保使用版本控制。 您會發現自己遇到了很多問題-在解決所有問題之前,您應該一直期待更多問題/崩潰。
不幸的是,您無法永遠避免出現內存問題,要追蹤其中的一些問題很痛苦-同時學習適當的內存管理(現在,這很困難)。 祝好運!
嘿,你知道嗎? 我才發現!!!!!!!! 我有多愚蠢...如果仔細查看entriesDetailedViewController.h文件,可以看到有一個聲明的textbodyBarButton ...好吧,它沒有發布,我已經忘了那個...
因此,很抱歉使您失去時間。
我剛剛添加了:
self.textbodyBarButton = nil;
[textbodyBarButton release];
現在我很好,當我回到rootViewController時,所有的內存都被釋放了。
因此,如果你們有一天遇到同樣的問題,那可能會很愚蠢。 只需檢查一下.h文件中聲明的內容即可。
哇,花了3天時間...
非常感謝大家,再次感謝您的耐心配合。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.