Code working on iPhone 5, not on iPod touch 4 - iphone

I'm testing my application on different devices. The app works fine on my iPhone 5, however, when I test it on my iPod touch 4g, I get this eror:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** [__NSArrayMinsertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x33f252a3 0x3bba397f 0x33e6f8d9 0x51e25 0x35e180c5 0x35e1814d 0x35e180c5 0x35e18077 0x35e18055 0x35e1790b 0x35e17e01 0x35d405f1 0x35d2d801 0x35d2d11b 0x37a1f5a3 0x37a1f1d3 0x33efa173 0x33efa117 0x33ef8f99 0x33e6bebd 0x33e6bd49 0x37a1e2eb 0x35d81301 0x4fc8d 0x3bfdab20)
libc++abi.dylib: terminate called throwing an exception
The code that's crashing is this one:
/********/
NSMutableArray *titulosCampoTextArray = [[NSMutableArray alloc] init];
for (int i = 0; i < campos.count; i++) {
SignupCell *cell = (SignupCell*)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
[titulosCampoTextArray addObject:cell.textField.text];
}
/********/
I'm using custom prototype cells (SignupCell.h), on a UITableView inside a UIView.
Can't find the error, or how to fix it.
EDIT: Both devices are running iOS 6.1.3, and I'm using Xcode 4.6.1.

UITableView's -cellForRowAtIndexPath: method returns nil if the cell isn't visible on screen when you call it.
My guess is that on the iPhone 5 your table can display all rows at once, while on the shorter iPod touch, the last one or two cells aren't visible and -cellForRowAtIndexPath: thus returns nil, which makes your app crash.
You shouldn't rely on -cellForRowAtIndexPath to request model data! Your view controller is responsible for the data, not the table view.
Use the same way to access the model data like you do for setting the table view cells' text in the -tableView:cellForRowAtIndexPath: data source method of your view controller.

Just do this:
NSMutableArray *titulosCampoTextArray = [[NSMutableArray alloc] init];
for (int i = 0; i < campos.count; i++) {
SignupCell *cell = (SignupCell*)[self.tableView
cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
if (cell.textField.text) {
[titulosCampoTextArray addObject:cell.textField.text];
}
}
I don't know why you apparently can add nil on an iPhone 5 but not on an iPod. It may be that for some other reason you just never happen to have a nil value for cell.textField.text when your app is running on the iPhone 5.

Related

NSZombie - should retain/release calls be paired by library?

TL:DR version: I used NSZombieEnabled to find source of EXC_BAD_ACCESS error and saw a library has 1 more release than retains. Can I assume that this library is causing the crash or can that release be associated with a retain from another library?
I am having some problems in my app with a UITableViewCell subclass instance getting messages after its retain count reaches 0. I ran the app with NSZombies and am currently trying to pair the retain/release calls to find where exactly is the error originating from. I noticed that there are only 2 retains and 3 releases with "Responsible Library" set to QuartzCore. Does it mean that that extra release call is the one that causes my app to crash? Or is it possible that a release has associated retain in another library?
Additional info:
My section headers are tappable, when one is selected, the row for this section is inserted into table view and any previously visible row is deleted. In other words, there can be only 1 section at a time that has 1 row, all other sections must have 0 rows.
The release/retain calls from QuartzCore that I paired are:
CALayer layoutSublayers (retains)
CA::Layer::layout_if_needed(CA::Transaction*) (releases)
The release without a pair is:
CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
The exact line where I get the crash is the endUpdates line in:
- (void)sectionHeaderView:(SectionHeaderView *)sectionHeaderView sectionOpened:(NSInteger)sectionOpened {
SectionInfo *sectionInfo = [self.sectionInfoArray objectAtIndex:sectionOpened];
sectionInfo.open = YES;
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:0 inSection:sectionOpened]];
/*
Create an array containing the index paths of the rows to delete: These correspond to the rows for each quotation in the previously-open section, if there was one.
*/
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
SectionInfo *previousOpenSection = [self.sectionInfoArray objectAtIndex:previousOpenSectionIndex];
previousOpenSection.open = NO;
previousOpenSection.category.model = nil;
[previousOpenSection.headerView toggleOpenWithUserAction:NO];
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:0 inSection:previousOpenSectionIndex]];
}
// Style the animation so that there's a smooth flow in either direction.
UITableViewRowAnimation insertAnimation;
UITableViewRowAnimation deleteAnimation;
if (previousOpenSectionIndex == NSNotFound || sectionOpened < previousOpenSectionIndex) {
insertAnimation = UITableViewRowAnimationTop;
deleteAnimation = UITableViewRowAnimationBottom;
}
else {
insertAnimation = UITableViewRowAnimationBottom;
deleteAnimation = UITableViewRowAnimationTop;
}
NSIndexPath *indexToDelete = [indexPathsToDelete firstObject], *indexToInsert = [indexPathsToInsert firstObject];
if (indexToDelete == nil) {
NSLog(#"no row to delete");
}
else {
NSLog(#"deleting row %d section %d", [indexToDelete row], [indexToDelete section]);
}
NSLog(#"inserting row %d section %d", [indexToInsert row], [indexToInsert section]);
// Apply the updates.
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[self.tableView endUpdates]; // this is the crash.
self.openSectionIndex = sectionOpened;
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:sectionOpened] atScrollPosition:UITableViewScrollPositionNone animated:YES];
}
The error happens on iOS7.
You can get a EXC_BAD_ACCESS at the endUpdates line if the index paths in the arrays are invalid (e.g. a section number of -1). You should NSLog your indexPathsToInsert and indexPathsToDelete and make sure they have valid values in them.
I have already found a fix to this problem. It seems that one of the subviews of the table cell was calling becomeFirstResponder after an asynchronous request has ended. Of course if the cell was freed already by that moment, the crash happened. I just assumed at first that the problem is because of unbalance in retains and releases but looks like that wasn't it.
And to answer the question in title: When running with NSZombieEnabled Instruments app already pair some retain/releases when it can assume they are connected. On one of the runs of my app, Instruments joined paired that release coming from QuartzCore with a retain coming from UIKit. Even though I can't be 100% sure that it's right, I assume that "Responsible library" tags being identical is not obligatory.
TL:DR - I'm pretty sure that retain can be paired with release coming from another library.

Inserting 8 or more objects into array crashes app

Simple question,
I loop thru my table view cells and add the objects to an array:
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger j = 0; j < [self.ammoTable numberOfSections]; ++j) // loop thru sections
{
for (NSInteger i = 0; i < [self.ammoTable numberOfRowsInSection:j]; ++i)//in each section loop thru the cells
{
[cells addObject:[self.ammoTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
}
}
This works PERFECT, as long as the table view has only 7 or less cells, if i add 8 or more, the app crashes with this log to the console:
'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Any help is greatly appreciated!
The cellForRowAtIndexPath: method of UITableView returns nil if the index path refers to a cell that is currently not visible, therefore
[cells addObject:[self.ammoTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
crashes in that case.
it lead to crash because you have only seven rows at the screen, when it all added to array after that it returns nil. for solving what you can do is create a method which take input as indexpath and returns cell object without using reuse cell.
The magic is in cellForRowAtIndexPath:. For certain values this is returning nil. Check this method and fix it.

Which class must I extend?

(I am developing an app that presents chat messages in a table. But, this chat can't be started by the user, when the user receives a message the chat view opens. So, I made this code:
- (void) newMessageReceived:(NSMutableDictionary *)message
{
General *general = [General sharedManager];
NSString *firstmessage=[message objectForKey:#"msg"];
NSString *from=[message objectForKey:#"sender"];
NSArray *listItems = [from componentsSeparatedByString:#"#"];
NSString *fromsplit=[listItems objectAtIndex:0];
general.firstmess=firstmessage;
general.firstfrom=fromsplit;
NSLog(#"Mensaje recibido: %# de %#", [message objectForKey:#"msg"], fromsplit);
ChatViewController *cvc=[[ChatViewController alloc]initWithNibName:#"Chat" bundle:nil];
[[self navigationController]pushViewController:cvc animated:YES];
}
Everything is ok, until here. The ChatViewController extends UITableViewController. But, when a message is received i get the following exception:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UITableViewController loadView] loaded the "Chat" nib but didn't get a UITableView.
Then, i try to change the class extended to UIViewController (did this to check that the program enters the numberOfRowsInSection method) and then i receive:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ChatViewController setTableViewStyle:]: unrecognized selector sent to instance 0x9863200'
I think that solving the first exception would fix my problem. Any help?
Thank you.
In the second exception i think you have called [self setTableViewStyle:] method, while
you have made it UIViewController.
So try to call this method by tableViewOutlet.
[tableView setTableViewStyle:];
Hope this will help you
Solved it. i click the .xib file, under "objects", clicked "View". And then, in the Identity Inspector (the third one, starting from the left), in Custom Class, set it to UITableView. It was simply "View" before. And then, everything worked fine.

App Crashing when returning from background

My application is crashing when it returns back from the background at certain places:
-[UITableViewCellContentView updateToInterfaceOrientation]: unrecognized selector sent to instance 0x165470
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCellContentView updateToInterfaceOrientation]: unrecognized selector sent to instance 0x165470'
The error is always similiar somtimes its with
[UIScrollViewDelayedTouchesBeganGestureRecognizer updateToInterfaceOrientation]
I'm really clueless as to why this is happening, any help would be much appreciated.
EDIT:
Ok, this is how I am creating my table view in the loadView method:
int tableCells = [formDS.tableItems count];
int tableHeight = FORM_TABLE_CELL_HEIGHT * (tableCells);
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, yCoord, FORM_TABLE_WIDTH, tableHeight) style:UITableViewStyleGrouped];
[table setBackgroundView:nil];
table.backgroundView.backgroundColor = UIColorFromRGB(FORM_BODY_COLOR);
table.backgroundColor = UIColorFromRGB(FORM_BODY_COLOR);
table.dataSource = self;
table.delegate = self;
[localContainerView addSubview:table];
It looks like you have some released object and because of that some other objects now present at the same address in memory receive the call for updateToInterfaceOrientation.
Try hitting COMMAND + SHIFT + B (or go to Product -> Analyze in XCode's top bar menu) to have XCode make a static analyze of your code and get some hints of what might go wrong.
Hope that's going to help!

Loop through UITextField's and store double values

I'm having trouble looping through a set of dynamically created UITextFields and storing those values as a double to be added to an array later on. I'm still pretty new to obj-c programming so bear with me if this question seems trivial. Thanks. This is what I have so far.
NSMutableArray *textFieldCashArray = [[NSMutableArray alloc] init];
double textFieldCash;
for (int y=0; y<25; y++) {
UITextField *myLabel = (UITextField *)[self.view viewWithTag:y];
textFieldCash = [myLabel.text doubleValue];
[textFieldCashArray addObject:[NSNumber numberWithDouble:textFieldCash]];
}
P.S and here is the error message I'm getting
Pro[962:b303] -[UIControl text]: unrecognized selector sent to instance 0x680f850
2012-04-01 16:05:46.305 iFinance Pro[962:b303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIControl text]: unrecognized selector sent to instance 0x680f850'
*** Call stack at first throw:
I think what's going on here is that the loop variable is being used as the tag, and the loop starts at zero. viewWithTag will answer either the receiver or one of it's subviews with a given tag, so if the view controller's main view has tag==0 (which it probably does), your first text request is being sent to that top-level view.
Try setting the text field tags to some non-zero value, starting at SOME_OFFSET. Then in your loop:
for (y=0; y<25; y++) {
UITextField *myLabel = (UITextField *)[self.view viewWithTag:y+SOME_OFFSET];
// ...
}
danh is most certainly right about the cause and solution to this problem. Just to add a little, cases like this can be somewhat avoided by checking the Class before casting.
if ([[self.view viewWithTag:y] isKindOfClass:[UITextField class]]) {
UITextField *myLabel = (UITextField *)[self.view viewWithTag:y];
textFieldCash = [myLabel.text doubleValue];
[textFieldCashArray addObject:[NSNumber numberWithDouble:textFieldCash]];
}
You should create array at first:
NSMutableArray *textFieldCashArray = [NSMutableArray array];
Edit
Your error log shows that you are receiving some another UIControl object (UIBtton for example) instead of UITextField. Check your tags on xib (or algorith if you set programmatically) and be sure that UITextField objects has corresponding tags