NSMutableArray removeObjectAtIndex: throws invalid argument exception - iphone

I'm writing an application to show some news from a portal. The news are fetched using a JSON file from the Internet and then stored into a NSMutableArray using the CoreData Model. Obviously a user can't delete the news from the JSON file on the Internet, but he can hide them locally. The problems come out here, where I have the following code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if( !moc ){
moc = [[NewsFetcher sharedInstance] managedObjectContext];
}
[[dataSet objectAtIndex:indexPath.row] setEliminata:[NSNumber numberWithBool:YES]];
NSError *error;
if( ![moc save:&error] ){
NSLog( #"C'รจ stato un errore!" );
}
[dataSet removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
The line:
[dataSet
removeObjectAtIndex:indexPath.row];
cause my apps to crash with the following error:
2010-07-12 19:08:16.021
ProvaVideo[284:207] * -[_PFArray
removeObjectAtIndex:]: unrecognized
selector sent to instance 0x451c820
2010-07-12 19:08:16.022
ProvaVideo[284:207] * Terminating
app due to uncaught exception
'NSInvalidArgumentException', reason:
'*** -[_PFArray removeObjectAtIndex:]:
unrecognized selector sent to instance
0x451c820'
I'm trying to understand why it doesn't work but I can't.
If I re-launch the app, the new is correctly logically cancelled.
Any suggestions?? Thanks in advance.
Interface:
#interface ListOfVideo : UITableViewController <NSFetchedResultsControllerDelegate> {
NSMutableArray *dataSet;
}
#property (nonatomic, retain) NSMutableArray *dataSet;
// In the .m file:
#synthesize dataSet;
Initialization in viewDidLoad:
dataSet = (NSMutableArray *) [[NewsFetcher sharedInstance]
fetchManagedObjectsForEntity:#"News"
withPredicate:predicate
withDescriptor:#"Titolo"];
[dataSet retain];
updateDatabase ... this is when checking for new news from the net, I add them in the MutableArray:
[dataSet addObject:theNews];

Your NewsFetcher returns you an immutable array, not a mutable instance. Use the following instead for initialization:
NSArray *results = [[NewsFetcher sharedInstance]
fetchManagedObjectsForEntity:#"News"
withPredicate:predicate
withDescriptor:#"Titolo"];
dataSet = [results mutableCopy];
An expression like A *a = (A*)b; only casts the pointer to a different type - it doesn't convert/change the actual type of the instance it points to.

Verify that dataSet is an NSMutableArray. The exception is getting thrown because it doesn't respond to removeObjectAtIndex.

jdot is correct dataSet must be NSMutableArray..
you must do it this way..
dataSet = [NSMutableArray arrayWithArray:[[NewsFetcher sharedInstance]
fetchManagedObjectsForEntity:#"News"
withPredicate:predicate
withDescriptor:#"Titolo"]];
Now the dataSet is a mutable instance of the array you got from NewsFetcher and it won't crash on removing objects.

Related

Application (tableview) is crashing while scrolling

I'm making an app which tries to read the information from the .plist file (put there parsed JSON).
The reading from file flows nice: got the array of dictionaries, but while trying to display it on tableview, the problems start. The initial view is loaded properly, but when I start scrolling, the app crashes.
#define DOCUMENTS [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filePathDocArray = [DOCUMENTS stringByAppendingPathComponent:#"filters.plist"];
NSString *filePathBundleArray = [[NSBundle mainBundle] pathForResource:#"filters" ofType:#"plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePathDocArray]) {
[[NSFileManager defaultManager] copyItemAtPath:filePathBundleArray toPath:filePathDocArray error:nil];
NSLog(#"File saved");
} else {
NSLog(#"File already exists");
filters = [NSArray arrayWithContentsOfFile:filePathDocArray];
}
}
Here I get all the info I need into filters array (checked by looping). Then:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [filters count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *myIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:myIdentifier];
}
NSInteger crow = indexPath.row;
NSDictionary *story = [filters objectAtIndex: crow];
cell.textLabel.text = [story objectForKey:#"Name"];
cell.detailTextLabel.text = [story objectForKey:#"Description"];
return cell;
}
#end
When the app starts everething is OK: I see the normel table view, but when I start scrolling it crashes
After series of breakpoint debugs I evaluated, that after the applications starts on Simulator, the link on array filters screws, so when I try to populate the next cell, the story dictionary can't be properly created.
What sort of problem it can be?
Here the console report:
2012-09-22 13:37:43.545 JSONExample[4559:207] -[__NSCFString
objectAtIndex:]: unrecognized selector sent to instance 0x6a083c0
2012-09-22 13:37:43.547 JSONExample[4559:207] *** Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason:
'-[__NSCFString objectAtIndex:]: unrecognized selector sent to
instance 0x6a083c0'
are you using ARC??
if not then autorelease the cell first!!
and if filters is not a retain property.. kindly make it one and synthesize it and again if ARC not used then release it in the dealloc block.. that should do it i suppose..
-[NSCFString objectAtIndex:]: unrecognized selector seems to be the same problem.
Your 'filters' variable is an NSString/CFString at the time you call objectAtIndex: - not an array, as you would assume. The solution given in the question linked to is to retain your filters array whenever it's set.
If you wote property for the filters like #property (nonatomic, retain) NSArray *filters; you need to write like self.filters = [NSArray arrayWithContentsOfFile:filePathDocArray];
Else you need to write like filters = [[NSArray arrayWithContentsOfFile:filePathDocArray] retain];
You need to keep in mind another thing..
if you do this step
NSDictionary *story = [[filters objectAtIndex: crow]retain];
every time your cellForRowAtIndexPath is called the retain count would increase by 1. But you will delloc it only once.
So there will be memory leaks in your applications.
I suggest you go through the memory management guide once. its a small document. at max it will take one day of yours. But will feel more confident of what to do and what not to do.
http://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/CFMemoryMgmt.pdf
Cheers!! And Happy Coding!!

Selecting a single field in a fetch into an array to load a picker

trying to load a single field into an array and then loading that in a picker. I think its in the creation of the array that I have a problem.
This is my code:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescr];
[request setPropertiesToFetch:[NSArray arrayWithObject:#"name"]];
NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
self.pickerData = array;
The error I get is this:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject isEqualToString:]: unrecognized selector sent to instance 0x7bb8100'
Any help would be appreciated...
My guess is that you're assuming the objects in your pickerData array are NSString instances, when in fact they are NSManagedObject instances. In order to get the value of the name field, you should do the following:
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSManagedObject *managedObject = [self.pickerData objectAtIndex:row];
NSString *name = [managedObject valueForKey:#"name"];
return name;
}
Please go through the documentation of NSManaged Object-
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/Reference/NSManagedObject.html
Then fetch the data properly and pass to Picker.
Main issue is wrong kind of comparison of objects, due to which app is crashing.

NSMutableArray removeObjectAtIndex:indexPath.row crashes

I have a UITableViewController with an NSMutableArray in the header like this:
NSMutableArray *someArray;
Also I have the property declared:
#property (nonatomic, retain) NSMutableArray *someArray;
In the .m file I load the array in the method:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
someArray = [[NSMutableArray alloc] init];
[self loadArrayData];
[tableview reloadData];
}
The table populates great, adding is no problem, but when I try to delete a row, the app crashes on the following line:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[someArray removeObjectAtIndex:indexPath.row];
//update table etc..
If I use the debugger, I can see the array has some objects, and when I Log indexPath.row I get a value which is inside the array size.
I don't understand why it is crashing on this line... Who can help me?
The console outputs:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x6193890'
I had a very similar problem and I was initiating my array with CoreData like this:
self.allContacts = (NSMutableArray*)[cdc.managedObjectContext executeFetchRequest:fetchRequest error:&error];
trying to cast the result from CoreDataController fetch request to NSMutableArray.
Turns out I need the function called "mutableCopy" at the end of fetch request.
self.allContacts = (NSMutableArray*)[[cdc.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
I don't think cast to (MutableArray *) is required but I have it just in case.
Hope this helps.
I had the same issue a week back. What I did was this:
Declared a NSMutableArray* globalArray as a global within the same tableViewController.m implementation file. Then inside
if (editingStyle == UITableViewCellEditingStyleDelete) {
globalArray = [[NSMutableArray alloc] initWithArray:someArray];
[globalArray removeObjectAtIndex:[indexPath row]];
}
And then I copied back this globalArray into someArray before the reloadData call. Works.
not sure if that cause one of your issues, but if you have property for someArray then use self.someArray instead of just someArray .
Of course that after using self, you should auto release it like this :
self.someArray = [[[NSMutableArray
alloc] init] autorelease];
(call this inside your viewController
init method)
then try to :
[self.someArray removeObjectAtIndex:indexPath.row];
2.
try to call [self loadArrayData]; inside viewDidLoad.
It should be called prior to cellForRowAtIndexPath, and that way you won't need to call reloadData
if that still won't help, then post the code of loadArrayData

How can I resolve this 'unrecognized selector sent to instance' error?

The error reads Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MObject objectAtIndex:]: unrecognized selector sent to instance. So, what I get out of that is that an instance of MObject (a subclass of NSObject) is receiving an objectAtIndex: message that it isn't meant to handle.
The error occurs when I tap on a table row to go to its detail view, which consists of a UIWebView detailWebView. The code for didSelectRowAtIndexPath is as follows:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MObjectDetailVC *mObjectDetailVC = [[MObjectDetailVC alloc] initWithNibName:#"MObjectDetailVC" bundle:nil];
mObjectDetailVC.detailURL = [[NSURL alloc] initWithString:[[[mcData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] url]];
mObjectDetailVC.title = [[[mcData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] name];
[self.navigationController pushViewController:mObjectDetailVC animated:YES];
[mObjectDetailVC release];
}
It's taking the NSString url property of the selected instance of MObject and turning it into an NSURL for the detail view controller, which just does the basic [detailWebView loadRequest:[NSURLRequest requestWithURL:detailURL]].
If you have any suggestions, I'll be glad to hear them. And if you need further information, please let me know.
Take a look at the structure of mcData. It and its members are expected to be NSArrays according to your code, be sure that they are.
objectAtIndex: is defined on a NSArray. If the MObject class is a subclass of NSObject, then it will not have the objectAtIndex: method defined, which is what the error says.
Both the following calls would cause a crash:
mObjectDetailVC.detailURL = [[NSURL alloc] initWithString:[[[mcData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] url]];
mObjectDetailVC.title = [[[mcData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] name];
Make sure that both mcData and [mcData objectAtIndex:indexPath.section] return an object of NSArray or of its subclass.
You can put a check to prevent the crash via respondsToSelector:
You can read more at
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html
Putting a check before passing a particular message will help you to avoid crash.

How do I display data in a UITableView cell from an NSDictionary?

Hi i received 2000 of datas from udp and display the values in tableview .What is the easiest method to do this ?
Now i am using Two nsthreads and one thread for receive data via udp and stores it in NSMutableDictionary.Another thread update the tableview using these Dictionary values. But it crashes my app.
Here is some code i used
I stored Received values like this
NSMutableDictionary *dictItem
CustomItem *item = [[CustomItem alloc]init];
item.SNo =[NSString stringWithFormat:#"%d",SNo];
item.Time=CurrentTime;
[dictItem setObject:item forKey:[NSString stringWithFormat:#"%d",SNo]];
[item release];
Delegate method i used and i used CustomTableCells to display data as column vice.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [dictItem count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"CustomTableCell";
CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
cell = [[[CustomTableCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
NSArray *keys = [dictItem allKeys];
CustomItem *item = [dictItem objectForKey:[keys objectAtIndex:indexPath.row]];
cell.SNo.text = item.SNo;
cell.Time.text = item.Time;
return cell;
}
The errror is
Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection was mutated while being enumerated.'
2010-07-23 02:33:07.891 Centrak[2034:207] Stack: (
42162256,
43320108,
42161198,
43372629,
41719877,
41719345,
9948,
3276988,
3237662,
3320232,
3288478,
71153942,
71153189,
71096786,
71096114,
71296742,
41650770,
41440069,
41437352,
51148957,
51149154,
2925426
)
terminate called after throwing an instance of 'NSException'
Can anyone help me ?
Thanks in advance.......
You probably have to use locking because when you access your dictionary from table view, it perhaps being mutated with other thread.
Try to look at NSLock docs. Before mutating your dictionary do [myLock lock]; and after mutating do [myLock unlock];. Similar in other thread: before enumerating dictionary do [myLock lock]; and after getting all values do [myLock unlock];.
myLock is a NSLock object and must be shared between your threads.
Mutable collections are not thread-safe by nature, so if you use them with multiple threads, you have to create an immutable copy first. For example, if you want to iterate through all the keys in your NSMutableDictionary, you would do this (assuming your NSMutableDictionary is called mutableDictionary):
NSDictionary *dictionary = [NSDictionary dictionaryWithDictionary:mutableDictionary];
for(id key in dictionary) {
// Do anything you want to be thread-safe here.
}
If you don't want to copy the dictionary, I suppose you could use locks or simply the #synchronized directive as follow:
#synchronized(mutableDictionary) {
// Do anything you want to be thread-safe here.
}
For more information, please have a look at the Apple documentation regarding multithreading and thread-safe objects: http://developer.apple.com/mac/library/documentation/cocoa/conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html