Objective-C内存管理:ViewController中的ViewController,位于UITabBarController中

时间:2011-07-10 23:31:17

标签: iphone objective-c object memory-management uiviewcontroller

我有一个带有三个ViewControllers(A,B和C)的UITabBarController。在ViewControllerB中,我有一个UIScrollView。 UIScrollView包含我的PhotoViewController的几个实例。这些PhotoViewController对象是从ViewControllerA调用的,而不是它们所在的ViewController B。

PhotoViewController实例有一个UIImage和两个按钮。首先,当我点击我的一个PhotoViewController实例中的按钮时,我收到了“线程1:程序接收信号:”EXC_BAD_ACCESS“'错误。查看stackoverflow时,只要存在内存管理问题,就会出现错误。

由于我是在一个循环中从ViewControllerA中调用的方法创建PhotoViewController对象,并释放这些对象,我想当我切换到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 个答案:

答案 0 :(得分:1)

要编写iOS应用,了解memory management rules

至关重要

在ViewControllerB,viewDidLoad中,您可以分配pvc。 再往下,您可以将pvc的视图添加为滚动条的子视图。这保留了pvc的观点,但不是pvc本身。然后当你释放pvc时,它的保留计数为零,当你稍后引用它时,它就消失了。崩溃。看起来你需要传入并保留对使用它的控制器中的pvc的引用。

答案 1 :(得分:0)

我不确定您使用PhotoViewController(子类UIViewController)而不是PhotoView(子类UIView)的原因。因为你没有使用viewcontroller的任何功能(没有生命周期方法和其他)。

如果您使用PhotoViewController继承UIView并删除了viewcontroller的方法,它将起作用,并且不会导致任何内存问题,因为您已经在与 Rayfleck 的讨论中讨论过这个问题。 (它将由父视图控制器保留。)

如果您正在考虑事件,那么这些事件也将由视图本身处理。但是如果你想在你的控制器中处理它,那么你可以轻松委托,或传递你的控制器参考并在其上调用事件。

谢谢,