Objective-C Управление памятью: ViewController в ViewController, который находится внутри UITabBarController - PullRequest
1 голос
/ 11 июля 2011

У меня есть UITabBarController с тремя ViewController (A, B и C). В ViewControllerB у меня есть UIScrollView. UIScrollView состоит из нескольких экземпляров моего PhotoViewController. Эти объекты PhotoViewController вызываются из ViewControllerA, а не из ViewController B, где они находятся.

Экземпляры PhotoViewController имеют UIImage и две кнопки. И сначала, когда я нажал кнопку в одном из моих экземпляров PhotoViewController, я получил сообщение «Поток 1: Программа получила сигнал:« EXC_BAD_ACCESS »». Если посмотреть на stackoverflow, то эта ошибка появляется, когда возникают проблемы с управлением памятью.

Поскольку я создавал объекты PhotoViewController в цикле из метода, вызываемого в ViewControllerA, и высвобождал эти объекты, я решил, что к тому времени, когда я переключился на ViewControllerB, они уже были освобождены - и, следовательно, проблема с памятью.

Но это только мое предположение. Не могли бы вы сказать мне, если я должен просто прекратить выпуск объектов PhotoViewController внутри кода цикла? Потому что это то, что я сделал (только что прокомментировал эту строку), и программа «работает» отлично. Тем не менее, я все еще не уверен, является ли это правильным способом справиться с этим и вызывает ли это неизвестные проблемы управления памятью.

Вот мой код:

ViewControllerA.m

// Создание альбома в ViewControllerB, фотографии в альбоме являются объектами PhotoViewController

-(IBAction)showAlbum:(UIButton *)sender
{
    //Go goes here to get an album and display it in the UIScrollView
    albumID = @"ALBUM_ID";
    NSString* graphUrl = [NSString stringWithFormat:@"%@/photos?limit=10", albumID];
    [_facebook requestWithGraphPath:graphUrl andDelegate:self];    
}

...

- (void)request:(FBRequest *)request didLoad:(id)result {

    //Code for array of photos
    NSLog(@"%@",result);
    NSString *requestType = [request.url stringByReplacingOccurrencesOfString:@"https://graph.facebook.com/" withString:@""];

    if ([requestType isEqualToString:[NSString stringWithFormat:@"%@/photos?limit=10", albumID]]){
        NSArray *photoAlbumArray=(NSArray*)[result valueForKey:@"data"];
        [self.label setText:[NSString stringWithFormat:@"%i", [photoAlbumArray count]]];
        for(UIViewController *controller in self.tabBarController.viewControllers)
        {
            if([controller isKindOfClass:[ViewControllerB class]])
            {
                ViewControllerB *mtbvc = (ViewControllerB *)controller;
                [mtbvc setArray:photoAlbumArray];
                self.tabBarController.selectedIndex = 1;//switch over to the second view to see if it worked
            }
        }
    }
...
@end

ViewControllerB.m

// цикл, в котором я создаю объекты PhotoViewController

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];
    arrayCount = [array count];
    scroller.delegate=self;
    scroller.pagingEnabled=YES;
    scroller.directionalLockEnabled=YES;
    scroller.showsHorizontalScrollIndicator=NO;
    scroller.showsVerticalScrollIndicator=NO;

    //should have an array of photo objects and the number of objects, correct?
    scrollWidth = 0;
    scroller.contentSize=CGSizeMake(arrayCount*scroller.frame.size.width, scroller.frame.size.height);

    for (int i = 0; i < arrayCount;i++) {
        PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:@"PhotoViewController" bundle:nil];        
        UIImageView *scrollImageView = [[UIImageView alloc] initWithFrame:CGRectOffset(scroller.bounds, scrollWidth, 0)];
        CGRect rect = scrollImageView.frame;
        pvc.view.frame  = rect;
        [pvc view];
        pvc.label.textColor = [UIColor whiteColor];
        id individualPhoto = [array objectAtIndex:i];
        NSLog(@"%@",individualPhoto);
        NSArray *keys=[individualPhoto allKeys];
        NSLog(@"%@",keys);
        NSString *imageURL=[individualPhoto objectForKey:@"source"];
        //here you can use this imageURL to get image-data and display it in imageView  
        NSURL *url = [NSURL URLWithString:imageURL];
        NSData  *data = [NSData dataWithContentsOfURL:url];
        pvc.imageView.image = [[UIImage alloc] initWithData:data];
        pvc.label.text = [individualPhoto objectForKey:@"id"];
        //check to make sure the proper URL was passed
        //I have an imageView next to the UIScrollView to test whether that works - it does.
        [scroller addSubview:pvc.view];
        [scrollImageView release];

        //[pvc release];

        scrollWidth += scroller.frame.size.width;
    }


    if (arrayCount > 3) {
        pageControl.numberOfPages=3;
    } else {
    pageControl.numberOfPages=arrayCount;
    }
    pageControl.currentPage=0;
    //[self.view addSubview:scroller];
}

PhotoViewController.m

#import "PhotoViewController.h"


@implementation PhotoViewController
@synthesize label, imageView;

-(IBAction)likeButton:(UIButton *)sender
{
    //code goes here 
    for(UIViewController *controller in self.tabBarController.viewControllers)
    {
        if([controller isKindOfClass:[DemoAppViewController class]])
        {
            DemoAppViewController *davc = (DemoAppViewController *)controller;
            [davc likePicture:self.label.text];
        }
    }
    self.tabBarController.selectedIndex = 0;//switch over to the third view to see if it worked
}

-(IBAction)skipButton:(UIButton *)sender
{
    //code goes here
}

-(IBAction)likeCommentButton:(UIButton *)sender
{
    //code goes here
}

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

- (void)dealloc
{
    [super dealloc];
}

- (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];
    // Do any additional setup after loading the view from its nib.
}

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

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end

PhotoViewController.h

#import <UIKit/UIKit.h>
#import "DemoAppViewController.h"
#import "MyTabBarViewController.h"

@interface PhotoViewController : UIViewController {

    IBOutlet UILabel *label;
    IBOutlet UIImageView *imageView;
    UIButton *likeButton;
    UIButton *skipButton;
    UIButton *likeCommentButton;
}

@property (nonatomic, retain) UILabel *label;
@property (nonatomic, retain) UIImageView *imageView;

-(IBAction)likeButton:(UIButton *)sender;
-(IBAction)skipButton:(UIButton *)sender;
-(IBAction)likeCommentButton:(UIButton *)sender;


@end

Ответы [ 2 ]

1 голос
/ 11 июля 2011

Чтобы писать приложения для iOS, важно, чтобы вы понимали правила управления памятью .

В ViewControllerB, viewDidLoad, вы выделяете ПВХ.Далее вы добавляете представление ПВХ как подпредставление скроллера.Это сохраняет вид пвх, но не сам пвх.Затем, когда вы отпускаете пвх, счет удержания равен нулю, а когда вы ссылаетесь на него позже, он исчезает.Краш.Кажется, вам нужно передать и сохранить ссылку на ПВХ в контроллере, который его использует.

0 голосов
/ 13 июля 2011

Я не уверен, почему вы используете PhotoViewController (подклассы UIViewController) вместо PhotoView (подклассы UIView).Так как вы не используете ни одного из средств viewcontroller (без метода жизненного цикла и прочего).

Если вы подклассом PhotoViewController используете UIView и удалите методы viewcontroller, это будет работать и не вызовет проблем с памятью, как вы уже обсуждали в своем обсуждении с Rayfleck .(он будет сохранен родительским контроллером представления.)

Если вы думаете о событиях, то они также будут обрабатываться самим представлением.Но если вы хотите обработать его в контроллере, вы можете легко делегировать или передать ссылку на контроллер и вызвать событие для него.

Спасибо,

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