Problem with NSOrderedSet addObject when unarchiving from file - iphone

I have been searching everywhere on the web and trying everything that I can think of so far to no avail. Here is my problem:
In my program I have a class called Scale, Scale has several properties. The user can add scales to a tableView by clicking a button called addScale. When addScale is pressed, I add it to a OrderedMutableSet. I use the set to store the scales and prevent duplicate scales. I had to override the isEqual method and the Hash method to fool the computer into thinking that two Scales with the same properties are exactly the same. This works fine. But when I open the app and have had previously some scales in the tableView, I have archiving implemented so these scales reappear, as expected. This time, when addScale is pressed, I get an exception:
-[__NSOrderedSetI addObject:]: unrecognized selector sent to instance 0x746dbf0
2011-08-29 13:20:49.095 MusicLog[678:f203]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__NSOrderedSetI addObject:]: unrecognized selector sent to instance 0x746dbf0'
Here is the code for my isEqual method and my Hash method:
(tonic, mode, rhythm, octaves, and tempo are all ints)
- (NSUInteger)hash
{
NSUInteger prime = 31;
NSUInteger result = 1;
result = prime * result + tonic;
result = prime * result + mode;
result = prime * result + rhythm;
result = prime * result + octaves;
result = prime * result + tempo;
NSLog(#"%u", result);
NSLog(#"%u", NSUIntegerMax);
return result;
}
- (BOOL)isEqual:(Scale *)object
{
if ((tonic == [object tonic])
&& (mode == [object mode])
&& (rhythm == [object rhythm])
&& (octaves == [object octaves])
&& (tempo == [object tempo]))
return YES;
else
return NO;
}
Here is the code for my addScale method:
- (IBAction)addScale:(id)sender
{
Scale *chosenScale = [[Scale alloc] init];
[chosenScale setTonic:[myPicker selectedRowInComponent:0]];
[chosenScale setMode:[myPicker selectedRowInComponent:1]];
[chosenScale setRhythm:[myPicker selectedRowInComponent:2]];
[chosenScale setOctaves:[octavesSegmentedControl selectedSegmentIndex] + 1];
[chosenScale setTempo: (int) [tempoStepper value]];
[[ScaleStore defaultStore] addScale:chosenScale];
}
the addScale method of the ScaleStore just calls addObject from a NSOrderedMutableSet which is where all the scales are stored.
Any help you can give is greatly appreciated.
Thank you,
K

When you unarchive, the objects are restored to an immutable version (NSMutableSet becomes NSSet, NSMutableArray becomes an NSArray, etc.)
Just create a new NSOrderedMutableSet with objects from the restored set.

Related

objective c perform selector in background and autoreleasepool

I am developing an iphone application which has some data stored in a sqllite database. When my view loads i would like to load the data from the database on a background thread. The problem is the application keeps crashing and i dont know why.
The code:
-(id) init
{
if((self=[super init]))
{
[self performSelectorInBackground:#selector(loadList) withObject:nil];
}
}
-(void) loadList
{
#autoreleasepool
{
Loader * loader = [[Loader alloc] init];
NSMutableArray * array = [loader getItemList];
[array retain];
NSLog(#"Got %d items",[array count]);
[self performSelectorOnMainThread:#selector(createList:) withObject:array waitUntilDone:false];
[loader release];
}
}
-(void) createList: (NSMutableArray*) array
{
items = array;
int i;
Item * it;
for(i = 0; i < [items count]; i++)
{
it = [items objectAtIndex: i];
[it getName]; // crashes
// populate the list
}
}
Loader returns a NSMutableArray with Item objects. The application crashes when i call the item getName (which returns a NSString*). From what i understand it crashes because the item name properties is being released. What am i doing wrong?
Thanks!
It's likely to be a problem with whatever type of object you're using to populate array.
I'm unable to find finger-on-paper proof but I'm confident that performSelectorOnMainThread:withObject:waitUntilDone: retains its object. However if each of the items in array keeps a reference to loader then they need to take responsibility for retaining that object. It looks like you're attempting to keep it alive manually but — as Chuck alludes to — your call to performSelector... will return instantly and not wait for the call you've made to complete.
This particular bug appears to be that you're passing waitUntilDone:NO, so the array is being released immediately and consequently so are its items.
But in general, UIKit is not thread-safe, so this is just a touchy design. I would probably put the loading of this stuff in another class that handles the task for you instead of right in the view.
I'd put a breakpoint on the line:
it = [items objectAtIndex: i];
Then type
po it
in the debugger, and see what's in the name field. As a guess, I'd say one of two things: 1) the field that getName returns isn't initialized with an object (i.e. isn't a real NSString *) or that you're getting a C string from SQLite (which is what it usually returns) and you're trying to treat it as an NSString *. If it's the latter you can use [myCString stringWithUTF8String] to convert the C string into an NSString *

Iteration of NSMutableArray of UITextView causes app to crash

I want to iterate Uitextview NsmutableArray but the program crashes and it gives the following error,
"""-[__NSCFString text]: unrecognized selector sent to instance 0x861c2f0"""
Please check this code , and give some possible solution...
Thank You...
for ( x = 0; x < TextViewArray.count; x++)
{
// here TextViewArray is a NSMutableArray
UITextView *textField1 = [TextViewArray objectAtIndex:x];
float diff3;
diff3 = [textField1.text floatValue]; // The program crashes in this line ,"""""" -[__NSCFString text]: unrecognized selector sent to instance 0x861c2f0""""" , here I am checking for a float value but i want to use string value instead of float value in this line how to do this?
NSLog(#"diff3 is %f",diff3);
textField1.text = [[NSString alloc] initWithFormat:#"%.2f",diff3];
TXT_First_Tag = [TextViewArray objectAtIndex:x]; // here uitextview *TXT_First_Tag;
NSLog(#"txt3 is %d",x);
TXT_First_Tag.tag = x;
NSLog(#" p is %d", x);
//textField1.text = [[NSString alloc] initWithFormat:#"%.2f",diff2];
//NSLog(#"Diff is %f",diff2);
}
Your array contains a String at the given index, hence the error """-[__NSCFString text]: unrecognized selector sent to instance 0x861c2f0""". Check that the Array only contains UITextViews
put a breakpoint before the crash and do a "po" in the gdb shell once control reaches breakpoint. This way you will no if you are trying to access right object or not

out of bounds error repopulating array for objective c app (iPhone)

I am currently troubleshooting code written by another colleague that has an out of bounds error with the following code. it involves selecting an item in a UINavigatorController. It also involves use of coreData.
the code looks like this (some of the code had been remove for troubleshooting purposes and clarity)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// : so far no errors with these lines of code. indexPath returns [0,0] or [0,1];
NSLog(#" : *** DetailViewController/didSelectRowAtIndexPath() - executing method ...");
NSLog(#" : *** DetailViewController/didSelectRowAtIndexPath() - indexPath = %#",indexPath);
// : returns row number (as an integer)
NSLog(#": *** DetailViewController/didSelectRowAtIndexPath() indexPath.row = %d",indexPath.row);
// : managedObject returns coreData information.
// Directory *managedObject = (Directory *)[finalArray objectAtIndex:indexPath.row];
// NSLog(#": *** DetailViewController/didSelectRowAtIndexPath() managedObject = %#",managedObject);
// example return
/*
<Directory: 0x5919e50> (entity: Directory; id: 0x59195d0 <x-coredata://FE8A3A0C-A0E4-4E0E-A90D-8471227D2284/Directory/p3> ; data: {
ID = 48;
IsFile = 0;
LastChanged = "2011-01-04 14:39:00 +0000";
Name = "All Papers by Author";
ParentID = 7;
Type = pdf;
}
*/
// : returns the ID value from the managed object
self.num = [managedObject ID];
NSLog(#": *** DetailViewController/didSelectRowAtIndexPath() self.num (managedObject.ID) = %#",[managedObject ID]);
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:finalArray];
// : finalArray has two elements when this method runs
NSLog(#"eja: DetailViewController/didSelectRowAtIndexPath() finalArray length is %i",[finalArray count]);
[self.finalArray removeAllObjects]; // releases the objects, but makes the array empty;
// : finalArray after remove all objects runs
NSLog(#"eja: DetailViewController/didSelectRowAtIndexPath() finalArray length is %i",[finalArray count]);
// ** THE OUT OF BOUNDS ERROR OCCURS HERE **
[self.finalArray setArray:[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]];**
// NSLog(#": DetailViewController/didSelectRowAtIndexPath() finalArray is %#",self.finalArray);
// ... more code here, but not relevant.
// : release the temp NSMutable array
[tempArray release];
// : maybe release the finalArray?
}
When I debug the app, I believe finalArray is supposed to be cleared (removeAllObjects) and is supposed to be re-populated, but I get an out of bounds error
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]: index 1 beyond bounds for empty array'
Not sure where the error is coming from, so looking for some advice and tips...
EDIT: i added a new trace statement after the removeAllObjects statement
// : finalArray after remove all objects runs
NSLog(#"eja: DetailViewController/didSelectRowAtIndexPath() finalArray length is %i",[finalArray count]);
it returns a count of 0. So should I suspect then that because it has zero length it has no room to reallocate memory to add new items? I thought that was how Mutable arrays work (more or less).
EDIT 2: Instead of setArray, I also tried add ObjectsFromArray, replacing this:
[self.finalArray setArray:[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]];**
// with this
[self.finalArray addObjectsFromArray:[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]];
but I had a similar error returned (out of bounds)...
The -setArray: replaces the existing elements with the elements from the array you are passing in. Thus the -removeAllObjects is redundant, but this is not the cause of your problem.
The size of the array you send -setArray: to is completely irrelevant so the problem probably lies in the array you are getting the elements from i.e. the one you get from:
[self searchDatabase:[self.num intValue] withPredicate:#"ParentID"]
I would separate that out by assigning a temp variable and then examine it in the debugger before the -setArray: and after the -setArray: (set the option "break on OBjective-C exceptions").
I determined the answer to the issue (and it's kind of silly)... I should give some context to the code I wrote above.
The purpose of the code was to use a UINavigationController to display information about directories and files. The problem was in the logic of the code. finalArray was a list of what needed to be displayed (i.e. a list of directories or files) and tempArray held the current directory.
All I needed some additional code to address the length...
// the following code was placed BELOW the code listing in the original question
if ([finalArray] count == 0){
// other code here
finalArray = tempArray; // reassign the current value (a list of files in this case) back to the current array...
} else {
// we will assign finalArray with the value of TempArray first, as "we are not done recursing through"
finalArray = tempArray;
// other code here
}
The out of bounds error showed up as a result of navigating through to a child view in UINavigationController and hitting the "back" button. since the display was not updated with the new menu items (whether it be files or folder listings) "finalArray" was constantly out of whack with what was actually being displayed (hence out of bounds - there may be 2 entries but maybe finalArray referenced one entry, whether it was a file or folder).
Hope this makes sense and thanks to all who looked at this question...
regards
Edward

Array count throwing exception

* -[__NSArrayM count]: message sent to deallocated instance 0x5edd5e0
I am Getting this type of exception and its crashing my app. The code is:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == 0){
return ([billDetials count]+ 1);
}
int rows = ([billers count] + 1);
return rows;
}
[billers count] for this statement i am getting that exception...
Here billers is NSMutableArray having 6 objects. tableView consists of 2 sections.
so I should get the array count as 6 but its not happenning....
It sounds like the billers array isn't getting retained properly. Make sure it's either a retained property, or that you're retaining it properly when you create that array.
Read and fully understand this:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html%23//apple_ref/doc/uid/10000011i
It appears that the 'billers' NSArray is being deallocated before you call the count method on it. This could be due to autorelease or a manual release before you send the count method.
If you are initializing billers using "alloc" and "init" then you are likely releasing the object too soon. If you are initializing it using a convenience method or with "autorelease", then the object is being garbage collected too soon (you need to retain it).

EXC_BAD_ACCESS Error for no conceivable reason

OK, This is a method from my program that keeps giving the EXC_BAD_ACCESS error and crashing. I indicated the line below. questionsShown is a readwrite property and points to an NSMutableArray that I initialize with a capacity of 99 at an earlier point in the program. When I debug everything appears normal in terms of the property being allocated. I assumed there must be some issue with memory management but I am having serious trouble finding the problem. Thanks in advance for any help.
#synthesize questionList;
#synthesize questionLabel;
#synthesize questionsShown;
-(IBAction)next{
int numElements = [questionList count];
int r;
if (myCount == numElements){
[questionLabel setText:#"You have seen all the questions, click next again to continue anyways."];
[questionsShown release];
questionsShown = [[NSMutableArray alloc] initWithCapacity:99];
myCount = 0;
}
else {
do {
r = rand() % numElements;
} while ([questionsShown indexOfObjectIdenticalTo:r] != NSNotFound);
NSString *myString = [questionList objectAtIndex:(NSUInteger)r];
[questionLabel setText:myString];
myCount++;
[questionsShown addObject:r]; //results in crash with message EXC_BAD_ACCESS
myCount++;
}
}
The EXC_BAD_ACCESS is coming from dereferencing r, which is just an integer. Your compiler should be giving you a warning (make pointer from integer without a cast) on that line.
If questionsShown is supposed to be some kind of index set for you (which it appears to be), you might want to either use that class, or you will have to box your integer in an NSNumber object. So:
[questionsShown addObject:[NSNumber numberWithInt:r]];
and when you read it:
[questionsShown indexOfObjectIdenticalTo:[NSNumber numberWithInt:r]]
I recommend, however, that you take a look at the NSIndexSet documentation.
With a mutable index set, you could do:
[questionsShownIndexSet containsIndex:r]
and
[questionsShownIndexSet addIndex:r]