I have a UICollectionView on iOS7 which crashes randomly when intense scrolling. I enabled zombies and found that it gives me an error saying:
*** -[NSIndexPath section]: message sent to deallocated instance 0x17dbc970
I believe this is due to an Apple error described here. Apparently, the app crashes when someone highlights a cell while scrolling fast, and then the OS tries to unhighlight it when it moves off screen, when it ceases to exist. The proposed solution is to disable the userInteractionEnabled property of the cell and then handle the selection using UIGestureRecogniser.
Has anyone else faced this same issue? Also, I tried unsetting the userInteractionEnabled property and using a gesture recogniser, but this doesn't seem to work. Any idea how I can fix this?
EDIT: Code added on request
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = #"Gallery_Cell";
GalleryCell *cell= (GalleryCell *)[self.flowCollection dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
if (indexPath.row < self.collectionData.count) {
CellDetails *dets = [self.collectionData objectAtIndex:indexPath.row];
NSURL *mainImageURL = [NSURL URLWithString:dets.imageURL];
cell.image.contentMode = UIViewContentModeScaleAspectFill;
cell.image.clipsToBounds = YES;
if ([[[SDWebImageManager sharedManager] imageCache] imageFromDiskCacheForKey:[self cacheKeyForURL:mainImageURL]] == nil) {
[cell.image setImageWithURL:mainImageURL placeholderImage:nil];
}else{
[cell.image setImage:[[[SDWebImageManager sharedManager] imageCache] imageFromDiskCacheForKey:[self cacheKeyForURL:mainImageURL]]];
}
}
return cell;
}
EDIT: more code..
I defined the GalleryCell for reuse as follows:
[self.flowCollection registerNib:[UINib nibWithNibName:#"Thumbs_Cell" bundle:nil] forCellWithReuseIdentifier:#"Gallery_Cell"];
The GalleryCell class implementation is:
GalleryCell.h
#interface GalleryCell : UICollectionViewCell
#property (nonatomic, retain) IBOutlet UIImageView *image;
#end
GalleryCell.m
#implementation GalleryCell
#synthesize image;
-(void) setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
[self setNeedsDisplay];
}
-(void)prepareForReuse {
[super prepareForReuse];
[self.image cancelCurrentImageLoad]; // SDWebImage method to cancel ongoing image load
}
OK. I seem to have solved it. In case anyone faces this problem, here is the fix:
I implemented the following method in my UICollectionViewDelegate:
-(BOOL) collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}
This prevents any cell from highlighting, and hence, avoids the crash when the system tries to unhighlight it when it goes off-screen. But, when you do this it also stops calling the didSelectItemAtIndexPath method. So I had to use a UITapGestureRecogniser method to implement cell selection instead.
Hope this helps.
I would suggest returning the following:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath{
return !collectionView.dragging && !collectionView.tracking;
}
Related
Help me to get rid of with this dilemma that occurred yet when I tried to dequeued the cell (Custom Cell).Below are some steps and Indents that I did with my Project.
The very first is I drag and drop a UITableView in my ViewController and add the ViewController.h doing after this
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
Then I made a Custom Cell with 3 UILabels and change the height of the Cell to 65.
After that I made a property in ViewController.m
#property (nonatomic,strong) NSMutableArray *myTodoTitles;
Then in method(ViewDidLoad) I did.
myTodoTitles = [NSMutableArray arrayWithCapacity:10];
[myTodoTitles addObject:#"Go for ride"];
[myTodoTitles addObject:#"Do University Assignments"];
[myTodoTitles addObject:#"Watch Show"];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.myTodoTitles count]-1 inSection:1];
[self tableView:self.myTodoTable cellForRowAtIndexPath:indexPath];
After that I just did these things in my ViewController.m
#pragma mark - Table view data source
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *myIdentifier = #"TodoCell";
TodoCell *todoCell = (TodoCell*)[tableView dequeueReusableCellWithIdentifier:myIdentifier];
todoCell.todoTitleLabel.text = [self.myTodoTitles objectAtIndex:indexPath.row];
return todoCell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [myTodoTitles count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
But when I run the project it dequeued nothing.
Please help
Most likely that you have not connected your viewController to be the dataSource of your tableView. This could be done from Interface Builder or from the code. You can easily check it by adding self.myTodoTable.dataSource = self; at the very first of viewDidLoad method.
And also: what did you mean by `
[self tableView:self.myTodoTable cellForRowAtIndexPath:indexPath];`
in viewDidLoad ? Seems like you wanted to do
[self.myTodoTable reloadData];
There are to UITableView methods with similar name:
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
and
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
forIndexPath:(NSIndexPath *)indexPath
The first one will try to dequeue a reusable cell. If it returns nil you are responsible to create appropriate cell.
The latter one will always return a valid cell: you will have to register a certain class or NIB with that tableview beforehand though. Docs.
EDIT:
As ReDetection pointed out: first method will also return a valid cell as long as you had registered a proper class (or nib) with that tableview.
In your case that means that you should register TodoCell in viewDidLoad with your tableView.
If TodoCell is made without .xib:
[self.tableView registerClass:[ToDoCell class]
forCellReuseIdentifier:#"TodoCell"];
Or if it is made with .xib.
[self.tableView registerNib:[UINib nibWithNibName:#"TodoCell"
bundle:nil]
forCellReuseIdentifier:#"TodoCell"];
EDIT2:
Your code also seems to be missing the dataSource setting. Something like:
self.tableView.dataSource = self;
This will trigger initial reload.
You'd probably want to set a delegate (since your controller claims to adopt that protocol) in the same manner.
I've a collection view with custom cell class.
In each cell I've a player with a specific sound.
When made an Button and link to my code with an IBOutlet, it's doesn't fire even with the fact I have userInteractionEnabled = YES in all my views.
So I decided to play the sound in the collection view controller.
In my cell the player has a property
#property (strong, nonatomic) AVAudioPlayer *voicePlayer;
Then in the collection I have:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
LHFriendVoiceObject *currentFriendVoice = [[LHFriendVoiceObject alloc] initWithNSDictionnary:[self.friendsArray objectAtIndex:indexPath.row]];
[cell hydrateWithFriendVoiceObject:currentFriendVoice];
[cell.voicePlayer prepareToPlay];
//[self.voicesArray addObject:cell.voicePlayer]; tried to stock them in array but doesn't work
return cell;
}
If I play the sound in this method it's work, but I want the sound to be played when I select the cell.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
Here the sound doesn't play because voicePlayer is nil.
How I can keep my players ?
This code is the problem:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
That first line is wrong. You are calling dequeue. Big mistake! It makes a completely new cell. Do not make a new cell like that! Obviously that new cell will not have any AVAudioPlayer in it.
You already have a cell; it just got selected. Use the indexPath and cellForItemAtIndexPath: to learn out which cell got selected. That is the one you want to talk to.
PS You really should figure out why the button approach didn't work, but it's no big deal at this point.
I'm getting an error when a button press loads the class posted below.
The code is supposed to load a slide out menu. This is the line that is causing my issues. I'm completely new to iOS / obj-c. I'm not sure why, but the method this line of code is in, loops through for each entry in the _menuItems array? The NSLog outputs for each item of the array, but then it runs another time and throws this error? Thats what I think is happening at least. If anyone could give me some pointers, I'd be grateful. Aside to all that, my project has two targets - I don't know why, I don't know how, and I don't know how to change it. Could that be the issue?
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
The console printout is this:
013-11-28 12:11:31.902 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.908 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.911 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.917 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.921 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.924 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.929 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.931 DatabaseTest[57858:a0b] The code runs through here!
2013-11-28 12:11:31.932 DatabaseTest[57858:a0b] *** Assertion failure in -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:5261
2013-11-28 12:11:31.936 DatabaseTest[57858:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier tag - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
.
#import "SidebarViewController.h"
#import "SWRevealViewController.h"
#interface SidebarViewController ()
#property (nonatomic, strong) NSArray *menuItems;
#end
#implementation SidebarViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
self.tableView.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
self.tableView.separatorColor = [UIColor colorWithWhite:0.15f alpha:0.2f];
_menuItems = #[#"title", #"news", #"comments", #"map", #"calendar", #"wishlist", #"bookmark", #"tag"];
}
- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[_menuItems objectAtIndex:indexPath.row] capitalizedString];
if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[dvc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
};
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.menuItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [self.menuItems objectAtIndex:indexPath.row];
NSLog(#"The code runs through here!");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
#end
You must use
static NSString *CellIdentifier = #"messageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Do not use if your cell is not registered a class or nib with Cell ID;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
Apple Documentation:
Important
You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
Edited:
This is wrong:
NSString *CellIdentifier = [self.menuItems objectAtIndex:indexPath.row];
Unless you have registered a cell for each row this isn't going to work.
You need to use a cell identifier that has been registered either in code or from the storyboard / xib.
also - the way you are doing this now takes no advantage of cell reuse if each cell loads a cell with a unique identifier.
I am not sure if you still after the answer for this question, but if you are here is the way you could solve your problem.
Your problem arises from the fact that the cell hasn't got an identifier or if it does, the identifier doesn't match the code in the NSArray *menuItems. To solve the problem:
you should go to the Document Outline (The small arrow at the bottom left of your storyboard)
then you should click on the 'Table View Cell - tag. (It should highlight the cell 'Tag'
Go to the Attributes Inspector and find 'Identifier'
Finally, change or ad the Identifier name, in your case 'tag'.
Et voila!, that should do the trick
Beware of spelling as Objective C is very tight on spelling, I mean you have to make sure the same way you spell the identifier, you must use the same spelling in your code.
Hope that help,
See picture: (I wanted to post one for you, but it seems like I cannot do so, Ooops!)
I am using core data in my app along with NSFetchedResultsController to populate a table. My database has 40k+ entries so the table is rather long. Each table cell has a thumbnail image that is loaded from the web using SDWebImage. All works great if I scroll slowly, if I begin to scroll fast within a couple of seconds I get a crash.
NSZombies isn't showing anything useful.
I'm guessing that it has to do with SDWebImage and loading from the web. The way SDWebImage works is by loading the image in the background then setting the downloaded image after it completes downloading (wordy). My thought is that the cells are being deallocated by the UITableView, then SDWebImage tries to set the image on the deallocated cell. So if I can determine when the UITableViewCell is going to be deallocated I can stop the SDWebImage downloading process and hopefully fix the issue.
I've tried to add
- (void)dealloc {
NSLog(#"dealloc");
}
to catch when the cell is going to be deallocated but I never get anything.
EDIT
I have my -(void)dealloc method in a subclass UITableViewCell.
EDIT
Here is where/how I create the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* inventoryCellID = #"InventoryCustomCellID";
InventoryCustomCell* cell = (InventoryCustomCell *)[tableView dequeueReusableCellWithIdentifier:inventoryCellID forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(InventoryCustomCell *)cell atIndexPath:(NSIndexPath *)indexPath {
[cell formatCellWithProduct:[fetchedResultsController objectAtIndexPath:indexPath] enableAdding:NO];
cell.openThumbnailButton.tag = indexPath.row;
[cell.openThumbnailButton addTarget:self action:#selector(presentThumbnailViewWithCell:) forControlEvents:UIControlEventTouchUpInside];
}
In my custom cell this is the configuration method being called:
- (void)formatCellWithProduct:(Product*)product enableAdding:(bool)addingEnabled {
self.titleLabel.text = product.part_number;
self.partNumberLabel.text = [[[product.manufacturer allObjects] objectAtIndex:0] name];
//The SDWebImage UIImageView category method
[self.thumbImageView setImageWithURL:[NSURL URLWithString:product.photo] placeholderImage:[UIImage imageNamed:#"icon.png"]];
}
EDIT
Here is the SDWebImage method that downloads the image and sets it.
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock;
{
[self cancelCurrentImageLoad];
self.image = placeholder;
if (url)
{
__weak UIImageView *wself = self;
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
__strong UIImageView *sself = wself;
if (!sself) return;
if (image)
{
sself.image = image;
[sself setNeedsLayout];
}
if (completedBlock && finished)
{
completedBlock(image, error, cacheType);
}
}];
objc_setAssociatedObject(self, &operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
Table views don't tend to allocate and deallocate table view cells much. Creating cells is expensive, so they get reused when possible, rather than being discarded when they go off screen.
The UITableViewDelegate method -tableView:didEndDisplayingCell:forRowAtIndexPath: is the better place to update cells to cancel downloads or other no-longer-relevant operations.
It does look like each call to -setImageWithURL:etc:etc: is trying to cancel previous downloads for that image view, though.
You didn't explain where did you put dealloc method..
I consider you can try to add a category to your viewcontroller for debugging just for test if your cell's deallocation is called (not tu subclass UITableviewCell) .
For example:
#implementation UITableViewCell(Dealloc)
- (void)dealloc {
NSLog(#"dealloc");
[super dealloc];
}
#end
Do you use ARC? If no than you forgot
InventoryCustomCell* cell = (InventoryCustomCell *)[[tableView dequeueReusableCellWithIdentifier:inventoryCellID forIndexPath:indexPath] autorelease];
So I have a UITableView which should loop through a single NSMutableArray and use each of them as row labels. Currently the only way I can get this to run is with 0 or 1 rows, 2 or higher throws out an error saying the array index is off. I tried NSLog to output my array and can confirm it's reading all the Strings.
// table methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell...
NSString *cellValue = [harvestRecipeList objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
The array code is stored in the exact same file (MasterViewController.m) which I added below.
- (void)viewDidLoad
{
[super viewDidLoad];
harvestRecipeList = [[NSMutableArray alloc] init];
[harvestRecipeList addObject:#"Ice Cream"];
[harvestRecipeList addObject:#"Walnut Cake"];
[harvestRecipeList addObject:#"Cookies"];
[harvestRecipeList addObject:#"Salad"];
[harvestRecipeList addObject:#"Grilled Fish"];
//Set the title
self.navigationItem.title = #"BTN Recipes";
}
I would love any help on this it's been bugging me. I was using [harvestRecipeList count] but this throws the same array index error. And as I mentioned I can get the app to run perfectly fine with 0 or 1 rows - thanks in advance for any help!
EDIT: here is the error I'm getting in the output window after building:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
EDIT2: included below my property setup for harvestRecipeList
//MasterViewController.h
#interface MasterViewController : UITableViewController {
NSMutableArray *harvestRecipeList;
}
#property (nonatomic, retain) NSMutableArray *harvestRecipeList;
// and also my MasterViewController.m
#synthesize harvestRecipeList;
EDIT3
here's my source code zipped for this project. It's called treehouse, just a testing name for now but you can dl from my cloudapp here.
Updated Solution:
So I have checked your code and found the problem. Do the following:
Go into your storyboard and select the Master Table View (click where it says Static Content)
Click on the Attributes Inspector (looks like a downward arrow sort of) and change the content from Static Cells to Dynamic Prototypes
Click on the prototype cell and type Cell into Identifier field (this is what you are using as a cell ID
Also change the Accessory from None to Disclosure Indicator
In your tableView:numberOfRowsInSection return self.harvestRecipeList.count
In tableView:cellForRowAtIndexPath: you can remove the following two lines (as they are provided by the Storyboard):
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
Recreate your Push segue from your Master Cell to your Detail View Controller
It should all now work fine - and I've tested that it works. The basic problem was you had specified Static Cells rather than Dynamic Prototypes and the rest of the instructions are just mopping up. The NSRangeException was caused by only having a single cell so that was all that was displayed.
Hope this helps.
Previous Solution:
So, a few comments but, first, if you've updated your code can you post an update?
Your harvestRecipeList that you add objects to in ViewDidLoad does not appear to be the same harvestRecipeList that you synthesised - it will be local to the method so your instance variable will always be nil. You should always use self.harvestRecipeList - do this everywhere. This could easily explain your NSRangeException. Also see #4 below.
In your tableView:numberOfRowsInSection: you should return self.harvestRecipeList.count
If you are using the iOS5 SDK, you do not need to check if cell == nil as dequeueReusableCellWithIdentifier: is guaranteed to return non-nil cell. You do need to check if you are on the iOS4 SDK.
Change your #synthesize harvestRecipeList; to #synthesize harvestRecipeList = _harvestRecipeList; as this will assist with #1 and checking you are accessing the ivar.
Try #1 & #2 as a minimum and then post an update on the problems you are having. Hope this helps.
I examined the code you put in the ZIP file. I immediately noticed your using the iOS 5 Storyboard feature. I haven't got Xcode 4 nor the iOS 5 SDK, so I could not test that part of your application.
However, I went on and coded your Storyboard part by hand. I have tested your MasterViewController solely and found no errors. I added in the AppDelegate this method to replace the Storyboard automatical features and just show the view controller where you think the error is coming from.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MasterViewController *myVC;
_window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] applicationFrame]];
myVC = [[MasterViewController alloc] initWithStyle:UITableViewStylePlain];
[_window setAutoresizesSubviews:YES];
[_window addSubview:myVC.view];
[_window makeKeyAndVisible];
return YES;
}
To prove your MasterViewController.m contains no error, I add this screenshot:
Conclusion: Your error is to be found somewhere else, probably in your Storyboard file. However I have never used that new functionality so I cannot help you with that. I suggest you review your Storyboard and put all attention to that file.
Okay, if your log messages display an array with five objects right before you try to query the second, and you application gives you an NSRangeException the bug is definitely not to be found in the code you show us.
Try to find it by placing various logs before and after any -[NSArray objectAtIndex:] and see which log doesn't come through after the call. There's your error.
Remember you can use
NSLog(#"%s", __PRETTY_FUNCTION__);
to show where you log message is coming from. Their also exists a line and file macro, but normally the function macro should help you enough.
Example:
NSLog(#"%s Before", __PRETTY_FUNCTION__);
[myArray objectAtIndex:anIndex];
NSLog(#"%s After", __PRETTY_FUNCTION__);
If your second log message doesn't come through, then you'll have found your error.
It is always best to use the setter and getter methods for your instance variables. It takes care of a lot of problems. My guess is that is your problem. So anywhere you want to use harvestRecipeList use self.harvestRecipeList
It would be useful to know what your property declaration is for harvestRecipeList