【问题标题】:Push ViewController generates runtime exceptionPush ViewController 产生运行时异常
【发布时间】:2017-08-30 02:35:33
【问题描述】:

我有一个选项卡式应用程序。在情节提要中,其中一个选项卡是导航控制器。在根视图上,会弹出一个 UIImagePickerController 以便用户拍摄或选择照片。

/*SnapItViewController.m*/
#import "SnapItViewController.h"
#import "FirstViewController.h"
#import "CollectionListViewController.h"
#import <sys/utsname.h>

@interface SnapItViewController ()

@end

@implementation SnapItViewController
@synthesize fetchedResultsController;
@synthesize currentLocation;

#pragma mark View lifecycle

- (void)awakeFromNib
{
    // Listen to takePicture notifications
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TakePicture) name:@"takePicture" object:nil];
    [super awakeFromNib];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    ipc = [[UIImagePickerController alloc] init];
    ipc.delegate = self;
    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
        ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
        [self presentViewController:ipc animated:YES completion:NULL];
    }else{
        ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        //launch image picker view controller
        [self presentViewController:ipc animated:YES completion:nil];
    }
    // Do any additional setup after loading the view.

}

- (void)viewWillAppear:(BOOL)animated {

   self.navigationController.navigationBarHidden = YES;

    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{    
    [super viewDidAppear:animated];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}
#pragma mark - ImagePickerController Delegate
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    UIImage* theImage = [info objectForKey:UIImagePickerControllerOriginalImage];

    if( picker.sourceType == UIImagePickerControllerSourceTypeCamera )
    {
        UIImageWriteToSavedPhotosAlbum(theImage, nil, nil, nil);
    }
    int height = -1;
    if([[NSUserDefaults standardUserDefaults] integerForKey:@"reduce_image"] == 0){
        height = 640;
    } else if ([[NSUserDefaults standardUserDefaults] integerForKey:@"reduce_image"] == 1) {
        height = 1024;
    } else {
        height = 1600;
    }

    UIImage* resizedImageForUpload = [UtilityFunctions scaleAndRotateImage:theImage maxResolution:height];
    NSData* imageDataForUpload = UIImageJPEGRepresentation(resizedImageForUpload, 1);   // reduced image! 

    NSString *userDataset = [UtilityFunctions retrieveFromUserDefaults:@"dataset"];

    [self didPickImage:imageDataForUpload atLocation:currentLocation
                     userDataset: userDataset];
    [picker dismissViewControllerAnimated:YES completion:nil];       
    [mLocationManager stopUpdatingLocation];     
    [self release];
    [self dismissViewControllerAnimated:YES completion:NULL];
}

-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
        [picker dismissViewControllerAnimated:YES completion:nil];      
}

- (void)pushChildControllerForCollectedLeaf:(CollectedLeaf*)theCollectedLeaf imageToUpload:(NSData*)imageToUpload animated:(BOOL)animated
{
    CollectionDetailViewController* childController = [[[CollectionDetailViewController alloc]initWithNibName:@"CollectionDetailViewController" bundle:nil] autorelease];
    childController.collectedLeaf = theCollectedLeaf;

    //// Pass the image from image picker to Collection Detail View, and it'll handles the upload. ////
    //// Set to nil for existing collections. ////
    if (imageToUpload)
    {
        childController.imageToUpload = imageToUpload;
    }

    childController.hidesBottomBarWhenPushed = YES;
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:nil action:nil];

    [self.navigationController pushViewController:childController animated:animated];
}

- (void)pushChildControllerForCollectedLeaf:(CollectedLeaf*)theCollectedLeaf imageToUpload:(NSData*)imageToUpload
{
    [self pushChildControllerForCollectedLeaf:theCollectedLeaf imageToUpload:imageToUpload animated:YES];
}

#pragma mark Leaflet Photo Picker Delegate

- (void)didPickImage:(NSData*)imageData atLocation:(CLLocation*)cLocation userDataset:(NSString *)userDataset
{
    //// Creates a new Collected Leaf ////
    CollectedLeaf* collectedLeaf = (CollectedLeaf*)[NSEntityDescription insertNewObjectForEntityForName:@"CollectedLeaf" inManagedObjectContext:[self.fetchedResultsController managedObjectContext]];

    //// Stores the geo-location to mCollectedLeaf ////
    if (cLocation)
    {
        collectedLeaf.latitude = [NSString stringWithFormat:@"%f", cLocation.coordinate.latitude];
        collectedLeaf.longitude = [NSString stringWithFormat:@"%f", cLocation.coordinate.longitude];
        collectedLeaf.altitude = [NSString stringWithFormat:@"%f", cLocation.altitude];

    }
    else
    {
        collectedLeaf.latitude = kGeoLocationNotAvailable;
        collectedLeaf.longitude = kGeoLocationNotAvailable;
        collectedLeaf.altitude = kGeoLocationNotAvailable;
    }

    collectedLeaf.collectedDate = [NSDate date];
    collectedLeaf.selectedSpecies = kUnknownSpecies;
    collectedLeaf.userDataset = userDataset;

    [self pushChildControllerForCollectedLeaf:collectedLeaf imageToUpload:imageData animated:YES];
}

@end

一旦用户选择了一张照片,它会将CollectionDetailViewController 推送到导航堆栈上。在CollectionDetailViewControllerviewDidLoad 方法中,它将CollectionDetailDataViewController 推送到显示UITable 的导航堆栈上。

/*CollectionDetailViewController.m */
- (void)viewDidLoad 
{
    containerView.frame = [self largeFrame];

    dataVC = [[CollectionDetailDataViewController alloc] init];
    dataVC.delegate = self;
    dataVC.collectedLeaf = self.collectedLeaf;
    dataVC.view.frame = [self normalFrame];

    [self.navigationController pushViewController:dataVC animated:NO];
    [super viewDidLoad];
}

当我单击 UITable 的一个单元格时,它会推送一个 SpeciesViewController 应用程序崩溃并显示 Thread 1: exc_breakpoint (code=exc_i386_bpt subcode=0x0)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    RankedSpecies *theRankedSpecies = [fetchedResultsController objectAtIndexPath:indexPath];
    SpeciesViewController* speciesController = [[[SpeciesViewController alloc]initWithNibName:@"SpeciesViewController" bundle:nil] autorelease];
    speciesController.theSpecies = theRankedSpecies.Species;
    [[tableView cellForRowAtIndexPath:indexPath] setSelected:NO animated:YES];
    [self.navigationController pushViewController:speciesController animated:YES];

}

认为这是一个释放问题,我试图注释掉所有涉及的释放方法,但问题仍然存在。我认为将 pushviewcontroller 替换为将 SpeciesViewController 添加为 CollectionDetailDataViewController 的子视图。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    RankedSpecies *theRankedSpecies = [fetchedResultsController objectAtIndexPath:indexPath];
    SpeciesViewController* speciesController = [[[SpeciesViewController alloc]initWithNibName:@"SpeciesViewController" bundle:nil] autorelease];
    speciesController.theSpecies = theRankedSpecies.Species;
    [[tableView cellForRowAtIndexPath:indexPath] setSelected:NO animated:YES];

    [self addChildViewController:speciesController];
    [self.view addSubview:speciesController.view];
    [speciesController didMoveToParentViewController:self];

}

它现在转到下一个视图,但应用程序随后崩溃并出现相同的异常代码。

我已经启用了 Zombies 并且还在断点导航器中添加了异常断点。我正在努力将我的代码版本放到 git 上,以便其他人可以体验我的问题并可能找到解决方案。

控制台中打印的错误:

2017-08-30 00:14:37.034 Leaflet-US[86918:4332982] *** -[SnapItViewController retain]: message sent to deallocated instance 0x7fae4470d4c0

崩溃堆栈跟踪:

【问题讨论】:

  • 自动发布?你在使用 ARC 吗?
  • 我继承了应用程序,所以有些代码是旧的。我尝试删除自动释放,但问题仍然存在
  • 你能发布你所有的崩溃日志吗?
  • 当然——如果发生崩溃,调试导航器 xcode 中的线程会跳转到整个崩溃日志吗?
  • SnapItViewController 在哪里?崩溃是关于它的,但我看不到相关代码。对了,你在CollectionDetailViewControllerviewDidLoad方法中漏掉了[super viewDidLoad]

标签: ios objective-c exception runtimeexception


【解决方案1】:
[picker dismissViewControllerAnimated:YES completion:nil];
[mLocationManager stopUpdatingLocation];
[self release];
[self dismissViewControllerAnimated:YES completion:NULL];

您同时以动画方式关闭两个视图控制器?也许您可以尝试在完成块中关闭第二次关闭。 self dismissViewControllerAnimated 是模棱两可的,因为它可以关闭其上的视图控制器或关闭自身。我想你想dismiss self,也就是SnapItViewController,所以你先释放SnapItViewController,然后给它发送dismiss消息,这显然是错误的。

您发布了SnapItViewController 代码,但仍然没有发布您调用它的位置。

【讨论】:

  • SnapItViewController 是“Snap It”选项卡上的根视图控制器 - 我没有编写代码来调用它,StoryBoard 为我设置了它
  • 我解散了 UIImagePickerViewController,然后解散了 SnapItViewController,然后在 didPickImage 中,我推送了一个新视图,这绝对不是经过深思熟虑的。但是如果我删除第二次解雇,我的程序就会崩溃。
【解决方案2】:

解决方案最终被删除

[self release]

[self dismissViewControllerAnimated:YES completion:NULL];

来自 SnapItViewController 中的 didFinishPickingMediaWithInfo

【讨论】:

  • 我不记得曾经看到过释放调用自我...这对我来说似乎是一个非常糟糕的主意。这样做有有效的用例吗?
  • 另外,假设您使用的是 ARC,无论如何您应该很少需要调用 release。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-02
  • 1970-01-01
  • 2013-03-02
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
相关资源
最近更新 更多