2012-08-01 49 views
3

我一直在搜尋與我的問題有關的所有主題,但我似乎無法找到解決方案。在我的應用程序中,我有一個.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 
+0

僅供參考:「.h file」=「頭文件」,滾動舌頭更容易 – benzado 2012-08-01 20:24:05

+0

哈哈。這是非常真實的:) – Barks 2012-08-02 01:09:00

回答

15

這的確是違反規定的要快枚舉過程中從一個可變的陣列添加或刪除的對象。在這種情況下,課程對象正在從數組中刪除,導致枚舉失效。

在viewWillAppear中,採取

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

,而是,嘗試

[purchasedLessons removeAllObjects]; 

如果由於某種原因,你需要將它們刪除一次一個,你可以嘗試

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

當回答一個問題時,請儘量提供儘可能多的信息,爲什麼你的答案有幫助,而不是隻發佈一段代碼來複制/粘貼。這樣,人們提出問題和搜索可以學到更多(這就是爲什麼我們都在這裏)。 – 2012-08-01 21:07:06

+0

點好了。我試圖添加更多信息。 – boxel 2012-08-01 21:30:58

+0

非常感謝@boxel :)工作就像一個魅力。我不能相信我錯過了這個:P很好的答案! – Barks 2012-08-02 01:11:53

相關問題