收集在枚举时发生变异

时间:2012-08-01 20:18:17

标签: iphone ios xcode ipad nsarray

我一直在搜索与我的问题相关的所有主题,但我似乎无法找到解决方案。在我的应用程序中,我有一个.h文件,其中包含构建“Lesson”对象库的信息(只是字符串和NSNumbers的集合)。当我只有一个对象时,似乎工作正常,但是当我添加第二个对象时,我得到了上述错误。

我扔了一些断点,似乎我通过我的viewDidLoad方法,但在该方法结束和我的tableView方法开始之间的某处,我收到了这个错误。我已经在下面发布了视图控制器的代码。如果您需要任何其他信息,请告诉我。在此先感谢:)

ViewController.h

#import <UIKit/UIKit.h>
#import "Lesson.h"
#import "PDFViewController.h"
#import "MediaPlayer/MediaPlayer.h"
#import "PracticeViewController.h"
#import "StoreViewController.h"

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

// Array to hold the purchased lessons.

@property (nonatomic,strong) NSMutableArray *purchasedLessons;
@property (nonatomic, strong) NSMutableArray *songLibrary;

@property (nonatomic, strong) NSNumber *purchaseMade;

@property (nonatomic, strong) ViewController *viewController;

// Lesson detail display items.

@property (strong, nonatomic) IBOutlet UIImageView *coverArt;
@property (weak, nonatomic) IBOutlet UILabel *lessonTitle;
@property (weak, nonatomic) IBOutlet UILabel *lessonSubtitle;
@property (weak, nonatomic) IBOutlet UILabel *durationLabel;
@property (weak, nonatomic) IBOutlet UILabel *notesLabel;
@property (weak, nonatomic) IBOutlet UILabel *timingLabel;
@property (weak, nonatomic) IBOutlet UILabel *keySignatureLabel;
@property (weak, nonatomic) IBOutlet UIImageView *difficultyImage;
@property (weak, nonatomic) IBOutlet UITextView *descriptionTextView;
@property (weak, nonatomic) IBOutlet UIImageView *dividerImage;
@property (weak, nonatomic) IBOutlet UIImageView *detailBackgroundImage;
@property (weak, nonatomic) IBOutlet UIImageView *detailsImage;

@property (strong, nonatomic) IBOutlet UITableView *tableView;

@property (nonatomic, strong) NSManagedObjectContext* managedObjectContext;



//Table Methods

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

// Variables and Methods for the Video Player

@property (strong, nonatomic) MPMoviePlayerViewController *player;

@end

ViewController.m

#import "ViewController.h"
#import "AppDelegate.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize coverArt;
@synthesize lessonTitle;
@synthesize lessonSubtitle;
@synthesize durationLabel;
@synthesize notesLabel;
@synthesize timingLabel;
@synthesize keySignatureLabel;
@synthesize difficultyImage;
@synthesize descriptionTextView;
@synthesize dividerImage;
@synthesize detailBackgroundImage;
@synthesize detailsImage;
@synthesize purchasedLessons;
@synthesize tableView;
@synthesize player;
@synthesize managedObjectContext;
@synthesize songLibrary;
@synthesize purchaseMade;
@synthesize viewController;

//TABLE METHODS

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return purchasedLessons.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // Create a cell.
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"purchased"];

    // Populate the cell with data.

    Lesson *temp = [[Lesson alloc] init];
    temp = [purchasedLessons objectAtIndex:indexPath.row];
    cell.textLabel.text = temp.title;
    cell.detailTextLabel.text = temp.subtitle;

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // Determine what row is selected and retrieve the correct Lesson object.
    Lesson *currentSelection = [[Lesson alloc] init];
    int row = [indexPath row];
    currentSelection = [purchasedLessons objectAtIndex:row];
    UIImage *tempCoverArt = [UIImage imageNamed:currentSelection.coverArtFilename];
    // Change the information in the details pane to the details for the current lesson.
    [coverArt setImage:tempCoverArt];
    lessonTitle.text = currentSelection.title;
    lessonSubtitle.text = currentSelection.subtitle;
    durationLabel.text = currentSelection.durationLabel;
    timingLabel.text = currentSelection.timing;
    keySignatureLabel.text = currentSelection.keySignature;
    descriptionTextView.text = currentSelection.lessonDescription;
    int diff = currentSelection.difficulty.intValue;
    switch (diff) {
        case 1:
            difficultyImage.image = [UIImage imageNamed:@"storeDiff1.png"];
            break;
        case 2:
            difficultyImage.image = [UIImage imageNamed:@"storeDiff2.png"];
            break;
        case 3:
            difficultyImage.image = [UIImage imageNamed:@"storeDiff3.png"];
            break;
        case 4:
            difficultyImage.image = [UIImage imageNamed:@"storeDiff4.png"];
            break;
        case 5:
            difficultyImage.image = [UIImage imageNamed:@"storeDiff5.png"];
            break;

        default:
            break;
    }


}

//END TABLE METHODS

- (void)viewWillAppear:(BOOL)animated {
    for (Lesson *lesson in purchasedLessons) {
        [purchasedLessons removeObject:lesson];
    }
    for (Lesson *lesson in songLibrary) {
        NSNumber *status = [[NSUserDefaults standardUserDefaults] objectForKey:lesson.productID];
        if ([status isEqualToNumber:[NSNumber numberWithInt:1]]) {
            [purchasedLessons addObject:lesson];
        }
    }
    [tableView reloadData];
}

- (void)viewDidLoad
{    
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.    

    purchaseMade = [NSNumber numberWithInt:0];
    viewController = self;
    purchasedLessons = [[NSMutableArray alloc] init];

    if (managedObjectContext == nil) 
    { 
        managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
    }

    // Load background images.
    UIImage *detailsDivider = [UIImage imageNamed:@"detailsDividerImage.png"];
    [dividerImage setImage:detailsDivider];

    UIImage *detailsBackground = [UIImage imageNamed:@"detailsBackgroundImage.png"];
    [detailBackgroundImage setImage:detailsBackground];

    UIImage *detailsPanel = [UIImage imageNamed:@"detailsDisplayImage.png"];
    [detailsImage setImage:detailsPanel];

    // Load default cover art.
    UIImage *defaultCoverArt = [UIImage imageNamed:@"coverArtDefault.png"];
    [coverArt setImage:defaultCoverArt];

    // Get current version ("Bundle Version") from the default Info.plist file
    NSString *currentVersion = (NSString*)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
    NSArray *prevStartupVersions = [[NSUserDefaults standardUserDefaults] arrayForKey:@"prevStartupVersions"];
    if (prevStartupVersions == nil) 
    {
        // Starting up for first time with NO pre-existing installs (e.g., fresh 
        // install of some version)

        // Import the song library.

        #import "songLibrary.h"

        // Save out the library to CoreData.

        NSError *error;
        if (![managedObjectContext save:&error]) {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }

        // Fetch the library and store it in the songLibrary array.

        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription 
                                       entityForName:@"Lesson" inManagedObjectContext:managedObjectContext];
        [fetchRequest setEntity:entity];
        NSArray *tempArray = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
        songLibrary = [[NSMutableArray alloc] initWithArray:tempArray];

        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:currentVersion] forKey:@"prevStartupVersions"];

        // Set the NSUserDefaults for the songLibrary

        for (Lesson *lesson in songLibrary) {
            [[NSUserDefaults standardUserDefaults] setObject:lesson.purchaseStatus forKey:lesson.productID];
        }
    }
    else
    {
        if (![prevStartupVersions containsObject:currentVersion]) 
        {
            // Starting up for first time with this version of the app. This
            // means a different version of the app was alread installed once 
            // and started.

            // Clear out any previously saved songs from the CoreData store.

            [managedObjectContext reset];

            // Import the updated song library.

            #import "songLibrary.h"

            // Save out the updated song library.

            NSError *error;
            if (![managedObjectContext save:&error]) {
                NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
            }

            // Fetch the updated library and save it to the songLibrary array.

            NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
            NSEntityDescription *entity = [NSEntityDescription 
                                           entityForName:@"Lesson" inManagedObjectContext:managedObjectContext];
            [fetchRequest setEntity:entity];
            NSArray *tempArray = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
            songLibrary = [[NSMutableArray alloc] initWithArray:tempArray];

            NSMutableArray *updatedPrevStartVersions = [NSMutableArray arrayWithArray:prevStartupVersions];
            [updatedPrevStartVersions addObject:currentVersion];
            [[NSUserDefaults standardUserDefaults] setObject:updatedPrevStartVersions forKey:@"prevStartupVersions"];

            // Set the NSUserDefaults for the songLibrary

            for (Lesson *lesson in songLibrary) {
                [[NSUserDefaults standardUserDefaults] setObject:lesson.purchaseStatus forKey:lesson.productID];
            }
        }
    }

    if (songLibrary.count == 0) {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription 
                                       entityForName:@"Lesson" inManagedObjectContext:managedObjectContext];
        [fetchRequest setEntity:entity];
        NSError *error;
        NSArray *tempArray = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
        songLibrary = [[NSMutableArray alloc] initWithArray:tempArray];
    }

    // Save changes to disk
    [[NSUserDefaults standardUserDefaults] synchronize];

    // Determine purchased songs from NSDefaults and add to purchasedLessons.

    for (Lesson *lesson in songLibrary) {
        NSNumber *status = [[NSUserDefaults standardUserDefaults] objectForKey:lesson.productID];
        if ([status isEqualToNumber:[NSNumber numberWithInt:1]]) {
            [purchasedLessons addObject:lesson];
        }
    }
}

- (void)viewDidUnload
{
    [self setLessonTitle:nil];
    [self setLessonSubtitle:nil];
    [self setCoverArt:nil];
    [self setDurationLabel:nil];
    [self setNotesLabel:nil];
    [self setTimingLabel:nil];
    [self setKeySignatureLabel:nil];
    [self setDifficultyImage:nil];
    [self setDescriptionTextView:nil];
    [self setDividerImage:nil];
    [self setDetailBackgroundImage:nil];
    [self setDetailsImage:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    // Segue to the materials screen.

    if ([segue.identifier isEqualToString:@"materials"]) {
        PDFViewController *pdfViewController = [segue destinationViewController];

        NSIndexPath *path = [self.tableView indexPathForSelectedRow];
        int row = [path row];
        Lesson *selected = [purchasedLessons objectAtIndex:row];
        pdfViewController.selectedLesson = selected;

        pdfViewController.fileToView = @"materials";

    }

    // Segue to the sheet screen.

    else if ([segue.identifier isEqualToString:@"sheet"]) {
        PDFViewController *pdfViewController = [segue destinationViewController];

        NSIndexPath *path = [self.tableView indexPathForSelectedRow];
        int row = [path row];
        Lesson *selected = [purchasedLessons objectAtIndex:row];

        pdfViewController.selectedLesson = selected;

        pdfViewController.fileToView = @"sheet";
    }

    // Segue to the practice screen.

    else if ([segue.identifier isEqualToString:@"practice"]) {
        PracticeViewController *practiceViewController = [segue destinationViewController];

        NSIndexPath *path = [self.tableView indexPathForSelectedRow];
        int row = [path row];
        Lesson *selected = [purchasedLessons objectAtIndex:row];
        practiceViewController.selectedLesson = selected;
    }

    else if ([segue.identifier isEqualToString:@"store"]) {
        StoreViewController *storeViewController = [segue destinationViewController];
        storeViewController.songLibrary = songLibrary;
        storeViewController.libraryViewController = viewController;
    }
}

@end

1 个答案:

答案 0 :(得分:15)

在快速枚举期间添加或删除可变数组中的对象确实违反了规则。在这种情况下,将从数组中删除课程对象,导致枚举变为无效。

在viewWillAppear中,点击

for (Lesson *lesson in purchasedLessons) {
    [purchasedLessons removeObject:lesson];
}

而是尝试

[purchasedLessons removeAllObjects];

如果出于某种原因,您确实需要一次删除一个,则可以尝试

while(purchasedLessons.count > 0) {
    [purchasedLesson removeLastObject];        
}