Утечка памяти в UIKit?

когда я тестировал свое приложение в инструментах на утечку памяти, я ничего не нашел (запуская с помощью симулятора). Но когда я запускаю его на мобильном телефоне, а затем проверяю, в объектах UIKit много утечек. Это происходит в каждом представлении. В симуляторе такие утечки не отображаются.

Ниже приведен скриншот прибора, на котором произошла утечка.

введите здесь описание изображения

Когда я перешел на secondViewController из HomeView, утечек не обнаружено. Если снова вернуться домой, эти многочисленные утечки обнаружены. Итак, означает ли это, что я должен освободить/обнулить все объекты пользовательского интерфейса, которые я использовал в этом втором представлении. К вашему сведению, ниже приведены объекты пользовательского интерфейса, которые я использовал во secondView.

1.Two Background UIImageView
2.One TitleBar UIImageView
3.3 UIButtons(Back,left and right button for iCarousel)
4.One iCarousel view
5.UIPageController(For this I have used a third Party code SMPageControl)
6.One title label. 

Примечание. У меня не код ARC.

Кто-нибудь сталкивался с этой проблемой раньше. Как я могу решить эту проблему, так как у меня есть эта проблема в каждом представлении в моем приложении. Из-за этого мое приложение часто получает память и часто дает сбой.

Спасибо.

Ниже приведен мой файл реализации этого представления.

РЕДАКТИРОВАТЬ1:

 @implementation CatalogueViewController

@synthesize deptCarousel    = _deptCarousel;
@synthesize carouselItems   = _carouselItems;
@synthesize categorymAr     = _categorymAr;
@synthesize spacePageControl = _spacePageControl;
@synthesize wrap;

- (void)dealloc {
    _deptCarousel = nil;
    [_categorymAr               release];
    _categorymAr                = nil;
    _deptCarousel.delegate      = nil;
    _deptCarousel.dataSource    = nil;
    [_deptCarousel              release];
    [_carouselItems             release];
    [viewGesture release];
    viewGesture = nil;
    [_spacePageControl release];
    _spacePageControl = nil;
    imgViewBG = nil;
    imgViewBG2 = nil;
    btnPrev = nil;
    btnNext = nil;
//    [self releaseObjects];
    [super dealloc];
}


- ( IBAction) btnBackClicked {
    [self.navigationController popViewControllerAnimated:YES];
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = NSLocalizedString(@"catalogue", @"Catalogue");

    // Do any additional setup after loading the view from its nib.

    _deptCarousel.type  = iCarouselTypeLinear;
    _deptCarousel.scrollSpeed = 0.3f;
    _deptCarousel.bounceDistance = 0.1f;
    _deptCarousel.scrollToItemBoundary = YES;
    _deptCarousel.stopAtItemBoundary = YES;
    [_deptCarousel setScrollEnabled:NO];

    UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeNext:)];
    swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
    [viewGesture addGestureRecognizer:swipeLeft];
    [swipeLeft release];

    UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipePrev:)];
    swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
    [viewGesture addGestureRecognizer:swipeRight];
    [swipeRight release];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    [viewGesture addGestureRecognizer:singleTap];
    [singleTap release];

    _carouselItems      = [[NSMutableArray alloc] initWithCapacity:1];
    _categorymAr        = [[NSMutableArray alloc] initWithCapacity:1];
    [self addCatalogues];
    _spacePageControl.numberOfPages = [_categorymAr count];
    [_spacePageControl setPageIndicatorImage:[UIImage imageNamed:IS_IPAD?@"Marker1.fw.png" : @"Markeri.png"]];
    [_spacePageControl setCurrentPageIndicatorImage:[UIImage imageNamed:IS_IPAD?@"Marker-Highlight.png" : @"Marker-Highlight_i.png"]];
    [_spacePageControl addTarget:self action:@selector(spacePageControl:) forControlEvents:UIControlEventValueChanged];

}



- (void)spacePageControl:(SMPageControl *)sender{
    [_deptCarousel scrollToItemAtIndex:sender.currentPage animated:YES];
}

- ( void ) addCatalogues {
    [_categorymAr addObjectsFromArray:[[DBModel database] categoryList]];

    for (int i = 0; i < [_categorymAr count]; i++) {
        [_carouselItems addObject:[NSNumber numberWithInt:i]];
    }
    [_deptCarousel reloadData];
}

- (void)viewDidUnload{

    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [self phoneType];
    [super viewWillAppear:animated];
    if (IS_IPAD) {
        UIInterfaceOrientation statusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        [self handleOrientation:statusBarOrientation];
    }
}

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


- ( void ) phoneType{

    if(!IS_IPAD){
        if(IS_IPHONE5){
            imgViewBG.image = [UIImage imageNamed:@"Background5_5.jpg"];
            imgViewBG.center = CGPointMake(162,265);
            imgViewBG2.image = [UIImage imageNamed:@"Background11_5.png"];
            _spacePageControl.center = CGPointMake(160, 478);
            _deptCarousel.center = CGPointMake(160, 355);
            viewGesture.center = CGPointMake(160, 355);
            btnPrev.center = CGPointMake(25, 355);
            btnNext.center = CGPointMake(295, 355);
        }
        else{
            imgViewBG.image = [UIImage imageNamed:@"Background5.jpg"];
            imgViewBG2.image = [UIImage imageNamed:@"Background9.png"];            
        }
    }

}


-(void)textFieldDidBeginEditing:(UITextField *)textField{

    textFieldSearch.placeholder = @"";
    UIButton *clearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
    [clearButton setImage:[UIImage imageNamed:IS_IPAD?@"Btn_X_Large.fw.png":@"Btn_X.fw.png"] forState:UIControlStateNormal];
    [clearButton addTarget:self action:@selector(btnClearTextField) forControlEvents:UIControlEventTouchUpInside];
    [textFieldSearch setRightViewMode:UITextFieldViewModeAlways];
    [textFieldSearch setRightView:clearButton];
    [clearButton release];

}

-(void)textFieldDidEndEditing:(UITextField *)textField{
    [textFieldSearch setRightView:nil];
    if ([textFieldSearch.text isEqualToString:@""]) {
        textFieldSearch.placeholder = NSLocalizedString(@"hud_search_for_a_product_here",@"");
    }
}

-(IBAction)btnClearTextField{
    textFieldSearch.text = @"";
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}



- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (IS_IPAD) {
        return YES;
    } else {
        return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
    }
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation )toInterfaceOrientation duration:(NSTimeInterval)duration{
    if (IS_IPAD) {
        [self handleOrientation:toInterfaceOrientation];
    }
}

- ( void ) handleOrientation:(UIInterfaceOrientation )toInterfaceOrientation {



    if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
        imgViewBG.image = [UIImage imageNamed:@"Background_Catalogue_P.jpg"];
        imgViewBG2.image = [UIImage imageNamed:@"Background_Overlay_P.fw.png"];
        btnPrev.center = CGPointMake(90, 640);
        btnNext.center = CGPointMake(677, 640);
        textFieldSearch.frame = CGRectMake(187, 54, 418, 25);
        _deptCarousel.frame = CGRectMake(235, 250, 300, 800);
        _spacePageControl.center = CGPointMake(385, 920);
        viewGesture.center = CGPointMake(385, 658);

    }else {
        imgViewBG.image = [UIImage imageNamed:@"Background_Catalogue_L.jpg"];
        imgViewBG2.image = [UIImage imageNamed:@"Background_Overlay_L.fw.png"];
        btnPrev.center = CGPointMake(54, 385);
        btnNext.center = CGPointMake(640, 385);
        textFieldSearch.frame = CGRectMake(240, 55, 567, 25);
        _deptCarousel.frame = CGRectMake(50, 250, 600, 300);
        _spacePageControl.center = CGPointMake(346, 660);
        viewGesture.center = CGPointMake(347, 405);

    }
}

- ( IBAction )btnDepartmentClicked:(id)sender {
    int btnTag = [sender tag];
    ProductCategoriesViewController *productView = [[ProductCategoriesViewController alloc] initWithNibName:@"ProductCategoriesView" bundle:nil];
    if ( btnTag == 0 ) {
        [productView setStrTitle:NSLocalizedString(@"women", @"Women")];
    }else if ( btnTag == 1 ) {
        [productView setStrTitle:NSLocalizedString(@"men", @"Men")];
    } else {
        [productView setStrTitle:NSLocalizedString(@"sports", @"Sports")];
    }
    [self.navigationController pushViewController:productView animated:YES];

    [productView release];
}


- ( BOOL ) textFieldShouldReturn:( UITextField * )textField {
    [textField resignFirstResponder];
    [Flurry logEvent:@"Product searched" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:textField.text,@"1", nil]];
    [self productSearch:textField.text isBar:NO isQR:NO];
    return YES;
}

- ( void ) productSearch:( NSString * )_searchText isBar:( BOOL )_isBar isQR:( BOOL )_isQr {
    if ([_searchText isEqualToString:@""]) {
        return;
    }

    NSMutableArray *ProductList = [[NSMutableArray alloc] init];
    [ProductList addObjectsFromArray:[[DBModel database] productSearch:_searchText isBar:_isBar isQR:_isQr]];
    if ( [ProductList count] == 0 ) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"product", @"")
                                                        message:NSLocalizedString(@"cannot_find_product", @"")
                                                       delegate:nil
                                              cancelButtonTitle:NSLocalizedString(@"ok", @"")
                                              otherButtonTitles:nil];
        [alert show];
        [alert release];        
    } else {
        GeneralProductListViewController *generalProductList = [[GeneralProductListViewController alloc] initWithNibName:IS_IPAD?@"GeneralProductListView~iPad": @"GeneralProductListView" bundle:nil];
        [generalProductList setMArProducts:ProductList];
        [self.navigationController pushViewController:generalProductList animated:YES];
        [generalProductList release];
    }
    [ProductList release];
  }


-(IBAction) spin:(id)sender {


    if([sender tag]==0)
    {

        [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+1 animated:YES];
//         [_deptCarousel scrollByNumberOfItems:1 duration:2.0];
        }

    else{
     [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]-1 animated:YES];

    }

}

-(void)swipeNext:(UISwipeGestureRecognizer *)recognizer{

     [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+1 animated:YES];

}

-(void)swipePrev:(UISwipeGestureRecognizer *)recognizer{

    [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]-1 animated:YES];

}

-(void) handleSingleTap:(UITapGestureRecognizer *)recognizer{

    if ([_categorymAr count] > 0) {

        ProductCategoriesViewController *prodCatView = [[ProductCategoriesViewController alloc] initWithNibName:IS_IPAD ?
                                                    @"ProductCategoriesView~iPad" : @"ProductCategoriesView" bundle:nil];
        Category *categoryObj = [_categorymAr objectAtIndex:[self.deptCarousel currentItemIndex]];
        [prodCatView setStrTitle:categoryObj.categoryName];
        [prodCatView setCategoryId:categoryObj.categoryId];
        [Flurry logEvent:@"Category List" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:categoryObj.categoryName,[NSString stringWithFormat:@"%d",categoryObj.categoryId], nil]];
        [self.navigationController pushViewController:prodCatView animated:YES];
        [prodCatView release];
    }
}
//-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//    pageControl.currentPage = [self.deptCarousel currentItemIndex] ;
//}

#pragma mark
#pragma mark NavigationBarViewDelegate metho

- ( void ) navigationBackClicked {
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark -
#pragma mark iCarousel methods

- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
    return [_carouselItems count];
}

- (NSUInteger)numberOfVisibleItemsInCarousel:(iCarousel *)carousel
{
    //limit the number of items views loaded concurrently (for performance reasons)
    return NUMBER_OF_VISIBLE_ITEMS;
}

- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index
{
    Category *categoryObj = [_categorymAr objectAtIndex:index];
    //create a numbered view
    UIView *view = nil;
    NSString *imagePath = [[APP_CACHES_DIR stringByAppendingPathComponent:@"catalogues"] stringByAppendingString:[NSString stringWithFormat:@"/%d.jpg", categoryObj.categoryId]];
    if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {
        view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:IS_IPAD?@"Gallery Placeholder.png":@"Gallery Placeholder.png"]] autorelease];
    } else {
        view = [[[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[[APP_CACHES_DIR stringByAppendingPathComponent:@"catalogues"] stringByAppendingString:[NSString stringWithFormat:@"/%d.jpg", categoryObj.categoryId]]]] autorelease];
    }



    if (IS_IPAD) {
        view.frame = CGRectMake(0, 0, 420, 420);
    } else {
        view.frame = CGRectMake(0, 0, 200, 200);
    }

//  UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(view.bounds.origin.x, view.bounds.origin.y+view.bounds.size.height, view.bounds.size.width, 44)] autorelease];
//  label.text = categoryObj.categoryName;
//    label.textColor = [UIColor blackColor];
//  label.backgroundColor = [UIColor clearColor];
//  label.textAlignment = UITextAlignmentCenter;
//    label.font = [UIFont fontWithName:@"Helvetica-Bold" size:IS_IPAD?26:14];
//  [view addSubview:label];


    return view;
}

- (NSUInteger)numberOfPlaceholdersInCarousel:(iCarousel *)carousel
{
    //note: placeholder views are only displayed on some carousels if wrapping is disabled
    return INCLUDE_PLACEHOLDERS? 2: 0;
}

- (UIView *)carousel:(iCarousel *)carousel placeholderViewAtIndex:(NSUInteger)index
{
    //create a placeholder view
    UIView *view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@""]] autorelease];
    UILabel *label = [[[UILabel alloc] initWithFrame:view.bounds] autorelease];
    label.text = (index == 0)? @"[": @"]";
    label.backgroundColor = [UIColor clearColor];
    label.textAlignment = UITextAlignmentCenter;
    label.font = [label.font fontWithSize:50];

    _spacePageControl.currentPage = index;


//  [view addSubview:label];
    return view;
}

- (CGFloat)carouselItemWidth:(iCarousel *)carousel
{
    //usually this should be slightly wider than the item views
    return ITEM_SPACING;
}

- (CATransform3D)carousel:(iCarousel *)_carousel transformForItemView:(UIView *)view withOffset:(CGFloat)offset
{
    //implement 'flip3D' style carousel

    //set opacity based on distance from camera
    view.alpha = 1.0 - fminf(fmaxf(offset, 0.0), 1.0);

    //do 3d transform
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = _deptCarousel.perspective;
    transform = CATransform3DRotate(transform, M_PI / 8.0, 0, 1.0, 0);

    return CATransform3DTranslate(transform, 0.0, 0.0, offset * _deptCarousel.itemWidth);
}

- (BOOL)carouselShouldWrap:(iCarousel *)carousel
{
    //wrap all carousels
//    return NO;
    return wrap;
}

- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index {
    if (index == [self.deptCarousel currentItemIndex]) {
        ProductCategoriesViewController *prodCatView = [[ProductCategoriesViewController alloc] initWithNibName:IS_IPAD ? 
                                                        @"ProductCategoriesView~iPad" : @"ProductCategoriesView" bundle:nil];
        Category *categoryObj = [_categorymAr objectAtIndex:index];
        [prodCatView setStrTitle:categoryObj.categoryName];
        [prodCatView setCategoryId:categoryObj.categoryId];
        [Flurry logEvent:@"Category List" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:categoryObj.categoryName,[NSString stringWithFormat:@"%d",categoryObj.categoryId], nil]];
        [self.navigationController pushViewController:prodCatView animated:YES];
        [prodCatView release];
    }
}

-(void) carouselDidScroll:(iCarousel *)carousel{

//    [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+3 animated:YES];

//    [_deptCarousel scrollByNumberOfItems:1 duration:1];

}

- (void)carouselCurrentItemIndexUpdated:(iCarousel *)carousel{

    _spacePageControl.currentPage = [self.deptCarousel currentItemIndex];
}

- ( IBAction ) myCart {
    if ( [[DBModel database] isShoppingListEmpty] ) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"at_shopping_cart", @"") 
                                                        message:NSLocalizedString(@"amsg_shopping_cart_empty", @"")
                                                       delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"") otherButtonTitles:nil];
        [alert show];
        [alert release];
        return;
    }
    MyCartViewController *myCartView = [[MyCartViewController alloc] initWithNibName:IS_IPAD ? @"MyCartView~iPad" : @"MyCartView" bundle:nil];
    [self.navigationController pushViewController:myCartView animated:YES];
    [myCartView release];
}

person NSUserDefault    schedule 13.07.2013    source источник
comment
Нам нужен код. Почему вы не используете ARC?   -  person Khaled Barazi    schedule 13.07.2013
comment
Мы не можем ответить на этот вопрос, не видя часть вашего кода. Что, вероятно, происходит (поскольку вы не используете ARC), так это то, что вы неправильно вызываете release/autorelease для объектов, созданных в вашем коде.   -  person Nicholas Hart    schedule 13.07.2013
comment
@ Spectravideo328 Пожалуйста, проверьте мой код, который я использовал для этого второго контроллера представления.   -  person NSUserDefault    schedule 13.07.2013
comment
@NicholasHart Пожалуйста, проверьте мой код, который я использовал для этого второго контроллера представления.   -  person NSUserDefault    schedule 13.07.2013
comment
Каково ваше сообщение о сбое? Можете ли вы дать нам BackTrace?   -  person Khaled Barazi    schedule 13.07.2013
comment
При сбое ничего не происходит. Он просто показывает два или три раза предупреждение о памяти и внезапно падает. Это может быть связано с вышеуказанной утечкой.   -  person NSUserDefault    schedule 13.07.2013
comment
Если у вас произойдет сбой из-за нехватки памяти, об этом будет сказано в журнале сбоев. Я не думаю, что это ваша проблема — вы упускаете всего несколько КБ. Я не вижу ничего очевидного в коде, который вы показали, но проблема может быть в другом месте (например, неправильное освобождение вашего контроллера представления). Я думаю, вам придется немного поработать, чтобы найти эту проблему. Используйте кнопку просмотра в инструментах, чтобы отобразить правую панель, затем выберите утечку, чтобы увидеть ее трассировку стека. raywenderlich.com/23037/how-to-use-instruments- в-xcode   -  person Nicholas Hart    schedule 15.07.2013
comment
@NicholasHart: я сошлюсь на эту ссылку и вернусь к вам. Но это происходит не только в этом представлении. Это происходит во всех представлениях. Большое Вам спасибо.   -  person NSUserDefault    schedule 15.07.2013
comment
Попробуйте установить для _deptCarousel.delegate и _deptCarousel.dataSource значение nil, затем отпустите _deptCarousel и только после этого установите для него значение nil.   -  person AntonPalich    schedule 15.07.2013
comment
@AntonPalich: Нет, не работает. Еще такие же утечки обнаруживаются.   -  person NSUserDefault    schedule 15.07.2013
comment
Является ли viewGesture IBOutlet? Если да, вы не должны выпускать его. Является ли [[база данных DBModel] categoryList] объектом автоматического выпуска? Если нет, вы должны добавить autorelease.   -  person Michal Zaborowski    schedule 15.07.2013
comment
@mientus: Да, viewGesture - это IBOutlet. Хорошо, я удалю выпуск для этого. Вместо этого я должен что-то сделать (например, удалитьFromSuperView)? и этот метод DBModel возвращает только NSMutableArray autorelease. Так что я думаю, что это нормально. Спасибо.   -  person NSUserDefault    schedule 15.07.2013
comment
Попробуйте также прокомментировать эту строку: '_spacePageControl addTarget:self action:@selector(spacePageControl:) ...' и посмотреть, есть ли у вас утечка памяти, потому что похоже, что проблема в _spacePageControl. РЕДАКТИРОВАТЬ: IBOutlet должен быть установлен только на ноль, вот и все.   -  person Michal Zaborowski    schedule 15.07.2013
comment
@mientus: я попытался прокомментировать эту строку и присвоил всем Outlets значение nil в Dealloc и проверил. все равно происходит утечка. Но все равно у SMPageControl утечка памяти даже после того, как я прокомментировал строки, относящиеся к этому классу.   -  person NSUserDefault    schedule 15.07.2013
comment
Вы проверили, какие линии были указаны с помощью инструментов? Вы должны показать расширенные детали в инструментах.   -  person Larme    schedule 15.07.2013
comment
Вы ДЕЙСТВИТЕЛЬНО должны использовать ARC. Преобразование простого проекта обычно занимает несколько секунд. Что касается вашей утечки: вы пробовали запускать статический анализатор (Product → Analyze)?   -  person Andreas Ley    schedule 15.07.2013
comment
@NSUserDefault, Instruments показывает массу утечек, поэтому я думаю, что ваше приложение, вероятно, пропускает контроллеры представления. Вы сохраняете их после нажатия на навигационный контроллер? Я бы повторил комментарии других о переходе на ARC. Это упростит большую часть вашего кода — возможно, даже решит вашу проблему.   -  person Nicholas Hart    schedule 15.07.2013
comment
@NicholasHart: Вы спрашиваете о сохранении самого viewController или его объекта? Я сохраняю некоторые NSObjects, такие как массив и т. Д. Даже я выпускаю эти объекты, когда выхожу из этого viewController. Итак, ваше предложение: переместить мой проект в ARC, верно?   -  person NSUserDefault    schedule 16.07.2013
comment
Спасибо за все ваши ответы и ценные предложения. Теперь я изменил свой проект на ARC, и теперь утечек не обнаружено.   -  person NSUserDefault    schedule 16.07.2013
comment
Но может ли кто-нибудь предположить, какова будет точная причина утечки в UIKit?   -  person NSUserDefault    schedule 16.07.2013
comment
Утечка не в UIKit, а где-то в вашем коде. Вы что-то неправильно сохранили или что-то не выпустили. Вот почему переход на ARC исправил это — компилятор теперь управляет временем жизни ваших объектов за вас.   -  person Nicholas Hart    schedule 16.07.2013
comment
@NicholasHart: Спасибо за ваше предложение. Но все же я сталкиваюсь с предупреждением о нехватке памяти для своего приложения. Я нашел много руководств по управлению памятью для кода ARC. Не могли бы вы предложить какой-нибудь хороший учебник по управлению памятью в ситуациях с нехваткой памяти устройства (iPad1 и iPhone3gs).   -  person NSUserDefault    schedule 17.07.2013
comment
Посмотрите видео WWDC 2013 «Устранение проблем с памятью». developer.apple.com/wwdc/videos   -  person Nicholas Hart    schedule 17.07.2013
comment
@NicholasHart: спасибо, я проверю   -  person NSUserDefault    schedule 17.07.2013


Ответы (3)


Первый:

у вас есть возможная и видимая утечка, но я не уверен, что это та же самая утечка, которую вы обнаружили в инструментах:

Эти две строки находятся в вашем методе viewDidLoad.

_carouselItems      = [[NSMutableArray alloc] initWithCapacity:1];
_categorymAr        = [[NSMutableArray alloc] initWithCapacity:1];

Но: viewDidLoad: вызывается каждый раз, когда представление загружается его контроллером. Если контроллер очищает представление (например, после предупреждения о памяти), при втором viewDidLoad ваши переменные экземпляра _carouselItems и _categorymAr теряют ссылку на ранее созданный NSMutableArray, вызывая утечку

Итак, измените эти строки и используйте синтезированные сеттеры:

self.carouselItems      = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
self.categorymAr        = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];

синтезированный установщик настроен на освобождение предыдущего объекта перед назначением нового.

Однако: возможно, у вас есть еще одна утечка. Если можно воспроизвести утечку просто (насколько я понимаю, утечка проявляется просто при переходе из одной ВК в другую), можно использовать функцию инструментов "heapshot".

Предполагая, что ваша утечка появляется при переходе от первого венчурного капитала ко второму и обратно:

  • открывать инструменты с помощью инструмента распределения
  • перейти из первого ВК во второй и вернуться обратно.
  • нажмите "отметить кучу" слева. Появится строка.
  • перейти еще раз из первого ВК во второй и вернуться обратно.
  • снова нажмите "Heapshot"
  • сделать это несколько раз (9-10)

Инструмент heapshot делает «моментальный снимок» живых объектов в момент нажатия кнопки и показывает только разницу. Если есть 2-3 новых объекта, вы увидите их в списке.

Это хорошая отправная точка для исследования утечки. Посмотрите на прикрепленное изображение:

Хипшот-анализ

Учтите, что вы должны пометить кучу несколько раз и отличить "ложное срабатывание", посмотрев на созданный объект, в моем примере вы можете увидеть возможную утечку (heapshot5, 1,66 КБ), но после просмотра содержимого ее нет --> это была фоновая задача, которая началась в тот момент.

Более того, задержки пула авторелиза и кеша некоторых объектов UIKit могут что-то показывать в heapshot, поэтому я советую попробовать несколько раз.

person LombaX    schedule 17.07.2013
comment
Использование сеттеров — это хорошо, но вам нужно использовать autoreleased-версию создания NSMutableArray, иначе это все равно утечка. self.carouselItems = [NSMutableArray array]; Обратите внимание, что использование initWithCapacity: почти всегда является ошибкой (особенно при такой малой емкости). (Как отмечалось в предыдущих комментариях, ARC в любом случае является правильным ответом.) - person Rob Napier; 17.07.2013
comment
вы правы, ему нужен авторелиз, потому что сеттер, настроенный как сохранение, отправляет еще одно сохранение на новый объект. исправляю пост. Насчет initWithCapacity и использования ARC (которое я могу предложить :-) Я тоже согласен, но (насчет ARC) я думаю, что расследование утечки и изучение некоторых концепций MRC всегда является хорошей практикой ;-), поэтому я предлагаю постер для перехода на ARC только после обнаружения утечки! - person LombaX; 17.07.2013
comment
Спасибо, ребята. Как вы все предложили, я преобразовал свой код в ARC. Теперь нет утечек памяти. Также следует следовать другим советам, чтобы справиться с предупреждением о нехватке памяти. - person NSUserDefault; 18.07.2013

Во-первых, как отмечалось ранее, используйте ARC. Нет ничего единственного, что вы могли бы сделать, чтобы улучшить управление памятью.

Независимо от того, используете вы ARC или нет, вы всегда должны использовать средства доступа для доступа к своим иварам (кроме init и dealloc). Как отметил @LombaX, вы неправильно устанавливаете свои ивары в viewDidLoad. Использование аксессуаров поможет в этом.

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

Я подозреваю, что у вас есть IBOutlet, настроенный как retain, и что вы не выпускаете его в dealloc. Это наиболее вероятная причина утечек, которые я вижу на ваших скриншотах. ARC обычно устраняет такие проблемы автоматически.

Вполне возможно, что у вас есть петля удержания. Как правило, это не будет выглядеть как утечка. Вы должны использовать heapshot, чтобы исследовать это. Ваши утечки довольно малы; они могут не быть фактической причиной предупреждений о памяти. То, что вы хотите исследовать (с помощью инструмента Allocations), — это то, что на самом деле значительно увеличивает использование вашей памяти.

Но сначала АРК. Затем аксессуары. Затем удалите все предупреждения сборки. Затем удалите все предупреждения Static Analyzer. Затем используйте инструмент Allocations.

Примечание: тот факт, что ответственной стороной является «UIKit», не означает, что это ошибка в UIKit. Это просто означает, что UIKit выделил память, которая позже просочилась. Причина утечки может быть в другом. (Тем не менее в UIKit есть несколько небольших утечек. В целом они не должны доставлять вам проблем, но вы, возможно, никогда не сможете избавиться от 100% небольших утечек в приложении для iOS.)

person Rob Napier    schedule 17.07.2013
comment
Большое вам спасибо, отличные предложения. Сообщите, решило ли это мою проблему. - person NSUserDefault; 18.07.2013

Один из простых способов определить, откуда берутся ваши утечки, — это использовать представление расширенных сведений в инструментах.

Для этого нажмите «Просмотр» -> «Расширенная информация» и появится правое меню с трассировкой стека «утечки». Там вы легко найдете код утечки для каждой утечки и если они происходят из вашего приложения.

person pdrcabrod    schedule 17.07.2013