[_UITableViewSeparatorView rangeOfString:]: unrecognized selector sent to instance - iphone

I am having a problem in executing the following code while searching in the table. This code works fine elsewhere. But currently it is giving an error as
[_UITableViewSeparatorView rangeOfString:]: unrecognized selector sent to instance 0x6041790
Following is the code that is troubling me. Please let me know the bug gidden in there.
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[tableData removeAllObjects];// remove all data that belongs to previous search
if([searchText isEqualToString:#""] || searchText==nil)
{
[displayTable reloadData];
return;
}
NSInteger counter = 0;
for(NSString *name in dataSource)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSRange r = [name rangeOfString:searchText];
if(r.location != NSNotFound)
{
if(r.location== 0)//that is we are checking only the start of the names.
{
[tableData addObject:name];
}
}
counter++;
[pool release];
}
[displayTable reloadData]; }
Thanks in advance!!
Looking forward to your responses.
thanks

It looks like you're over-releasing the strings that you have stored in dataSource. I would check any place that you use/create those strings to make sure that you aren't releasing them more times than you should.

It means that the memory where the string should reside in memory was freed and there is another object on that place (_UITableViewSeparatorView in your case). Make sure that you are not over-releasing the string in array
You can try to search with NSZombiesEnabled in instruments: link

What are you putting in dataSource? Evidently, it contains an object that is not an NSString.

Related

Why does this Code cause the EXC_BAD_ACCESS error?

Here's a piece of code I wrote for cleaning A string of unwanted chars and double spacing.
However, I seem to have misunderstood memory management somewhere and it keeps causing the EXC_BAD_ACCESS error. The Code works fine functionally when the release statements are removed but that would cause memory leaks.
-(NSString*) cleaningString:(NSString*) input {
NSCharacterSet* wantedCharacters=[[NSCharacterSet alloc] init];
wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
NSString* cleanStringOutput=[[NSString alloc] initWithString:#""];
NSString* currentLetter =[[NSString alloc] initWithString:#" "];
NSRange unwantedCharacters=[currentLetter rangeOfCharacterFromSet:wantedCharacters];
for (int i=0; i<input.length; i++) {
currentLetter=[NSString stringWithFormat:#"%c",[input characterAtIndex:i]];
unwantedCharacters=[currentLetter rangeOfCharacterFromSet:wantedCharacters];
doubleSpace=YES;
if (i<input.length-1) {
if (([currentLetter isEqualToString:#" "])&&([[NSString stringWithFormat:#"%c",[input characterAtIndex:i+1]] isEqualToString:#" "])) {
doubleSpace=NO;}
}
else {
if ([currentLetter isEqualToString:#" "]) {
doubleSpace=NO;
}
}
if ((unwantedCharacters.location!=NSNotFound)&&(doubleSpace))
{
cleanStringOutput=[NSString stringWithFormat:#"%#%#", cleanStringOutput, currentLetter];
}
}
if (cleanStringOutput.length>0){
if ([[NSString stringWithFormat:#"%c",[cleanStringOutput characterAtIndex:0]] isEqualToString:#" "]){
cleanStringOutput=[cleanStringOutput substringFromIndex:1];
}
}
[currentLetter release];
[wantedCharacters release];
[cleanStringOutput autorelease];
return cleanStringOutput;
}
Please forgive me if I just asked something painfully obvious.
P.S. And another question. Is it necessary to release the NSRange?
Right here
NSCharacterSet* wantedCharacters=[[NSCharacterSet alloc] init];
wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
You discard your original object and replace it with an autoreleased one
Which will crash when you call
[wantedCharacters release];
Do this
NSCharacterSet* wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
and forget the last
[wantedCharacters release];
There are several mistakes in your code that causes you to lose the reference to the allocated objects, and an example will follow, but a few things:
The easiest solution for all of them, is to use autorelease wherever you call alloc (and remove the release for those objects), for example:
NSString* cleanStringOutput=[[[NSString alloc] initWithString:#""] autorelease];
When you create a variable only to assign to it later, there is no need to allocate, for example:
NSCharacterSet* wantedCharacters; // no need for alloc here
wantedCharacters=[ NSCharacterSet characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
In general - if you didn't allocate the object, you don't release it.
currentLetter=[NSString stringWithFormat:#"%c",[input characterAtIndex:i]];
Returns an autoreleased string - no need to alloc/init it above.
NSString* currentLetter =[[NSString alloc] initWithString:#" "];
So calling
[currentLetter release];
Will probably cause problems.
You alloc/init a wantedCharacters object, then reassign it using a convenience function. The reassignment creates a zombie with the first object.
The convenience function puts the new object instance into the autorelease pool.
Then you call release. Since it was only retained once, it gets deallocated.
Later, the autorelease pool calls release on it, but it has already been deallocated. This causes the crash.

Why does this cause a crash?

I have these two buttons hooked up to these two methods (they're nearly identical)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
numberOfImage = [NSString stringWithFormat:#"%i",num];
//Load the image
[self loadImage];
}
If I hit either of them twice (or once each, basically if they get called a total of two times) I get an EXC_BAD_ACCESS. If I throw a retain on: numberOfImage = [[NSString stringWithFormat:#"%i",num]retain] it's fine though. Can someone explain why this is? I did an NSZombie on the instruments and traced it back to this stringWithFormat call. Thanks in advance!
+stringWithFormat: doesn't contain 'new', 'alloc', 'copy', or 'retain', so it should be expected that you have to retain the return value of it if you want the new NSString it creates to stick around.
Edited to include this handy link duskwuff kindly dug up: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
If numberOfImage is a properly declared property, e.g.
#property (copy) NSString *numberOfImage;
and it was properly synthesized (in the #implementation section for the class):
#synthesize numberOfImage;
then you can do:
- (void) moveOneImageNewer
{
self.numberOfImage = [NSString stringWithFormat: #"%i", [self.numberOfImage intValue] - 1];
// Load the image
[self loadImage];
}
The property setter will take care of retaining the string and, if necessary, releasing the previous string.
FWIW, why on earth is numberOfImage a string? Why not a simple int?
numberOfImage is an instance variable or property of your class, right?
You are setting it to a stringWithFormat (which returns an auto-released NSString) without claiming ownership of that object (by calling retain).
If you do not retain it, it will get auto-released before the method is called again (and then the first line will fail, as it tries to access the previously set, now auto-released value).
Consider using properties, they have auto-generated memory management code (including releasing the old NSString when you set the new one).
You haven't retained the string object in "moveOneImageOlder", so that object gets autoreleased at the end of the event cycle and points to nothing. That's why you get the EXC_BAD_ACCESS next time you try to use it.
Use a retain to claim ownership of the NSString. Remember to release when you're done though (you can use properties to help you with this)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
Add this in dealloc:
- (void)dealloc {
[numberOfImage release];
[super dealloc];
}
Well, the NSString class method "stringWithFormat" returns an autorelease NSString object if I'm right.
So the second call to your method would have numberOfImage pointing to nothing, as the autorelease NSString object it used to be pointing to has already been released and deallocated since you didn't retain it.
The part that is directly causing the crash is [numberOfImage intValue] when you call the method a second time, as you sending a message to an object (pointed to by numberOfImage) that no longer exist.

UISearchDisplay - application crash

i've got huge problem. I've copied some code from table search sample from Apple Resource pages.
here's the case:
#pragma mark -
#pragma mark Content Filtering
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
[self.chatMessagesArrayCopyForSearching removeAllObjects]; // First clear the filtered array.
if ([searchText length]==0)
{
}else
{
for (FriendMessage *friend in chatMessagesArray)
{
NSComparisonResult result = [friend.message compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
[self.chatMessagesArrayCopyForSearching addObject:friend];
NSLog(#"%#", friend.message);
}
}
}
}
application crash when for example i type one letter, and then the second letter. probably there something with friend.message becouse console says:
-[AccessibilityObjectWrapper message]: unrecognized selector sent to instance 0x5d8d580
FriendMessage is custom class, inherited from NSObject, and message is standard NSString *.
thanks for any provided help
mapedd
p.s. sorry if code isn't very readable
The fact that it says 'AccessibilityObjectWrapper' in your error tells you that there might have been a FriendMessage object there at some point but it's gone now :)
This is typically because there is a missing retain somewhere in your code.
Where do you create the array of FriendMessage objects - can you edit your question and add that code as well?
Thanks.

UISearchDisplayController and search performance with lots of data

I'm trying to figure out the best way to perform a fast search using a UISearchDisplayController.
I have a plist file with more than 36000 entries. I load this file in a dictionary and I perform the search in this dictionary. It works but it's kinda slow and there is lag between each touch event. I want an autocompletion effect so I need the search to be triggered for each touch event.
I tried using thread to perform the search in background with the following code :
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[NSThread detachNewThreadSelector:#selector(filter:) toTarget:self withObject:searchString];
return NO;
}
// Filter function looks like this
-(void) filter:(NSString *)search {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self.filteredList removeAllObjects]; // empty array of results
for (NSString *s in self.keys ) {
NSComparisonResult result = [s compare:search options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [search length])];
if (result == NSOrderedSame) {
[self. filteredList addObject:s ];
}
}
[ self.searchDisplayController.searchResultsTableView reloadData];
[pool release];
}
But my application crashes randomly with the following message:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (1) beyond bounds (0).
I'm sure it's because I dont use threading properly.
I also tried using [self performSelector:#selector(filter:) withObject:searchString afterDelay:0.5]; but I'm also facing application crashes.
What is the best way to handle this ? I'm not really good with threads but I think it's the best way to go, isn't it ? I also tried a solution with SQLite but the application is still not so responsive.
My data are actually zip codes and cities (36000 unique different cities but 6500 unique zip codes since multiple cities can have the same zip code). I want my search item to be either a zip code or a city name. I know that one big dictionary is definitely not the best structure. How could I organize my data for more efficiency?
Thank you for helping me with this.
The problem is that your search string is longer than one of your original strings in the array. When comparing from 0 to [search length] you are falling outside of s. You should first make sure that s is longer than search:
for (NSString *s in self.keys ) {
if ([s length]>=[search length]) {
NSComparisonResult result = [s compare:search options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [search length])];
if (result == NSOrderedSame) {
[self. filteredList addObject:s ];
}
}
}

Iphone App Crashes - But sometime works(50%-50%)

I am using following code for showing a next view(tableview) in Iphone app.
It sometime works and some time app crashes without any exception log
NSLog(#"Ok"); is log everytime
50% attempts application crashes
-(IBAction)statusInitiationButAction:(id)sender{
#try {
NSArray *tempArrIniId = [eventInitiationArray valueForKey:#"act_id"];
int s;
if([tempArrIniId containsObject:selectedInitiateId]){
s=[tempArrIniId indexOfObject:selectedInitiateId];
}
[tempArrIniId release];
NSString *selStatusId = [NSString stringWithString:[[eventInitiationArray objectAtIndex:s] objectForKey:#"status_id"]];
for (int i=0; i<[statusInitiationArray count]; i++) {
id statusDict = [statusInitiationArray objectAtIndex:i];
if ([selStatusId intValue] == [[statusDict objectForKey:#"id"] intValue]) {
[statusDict setValue:#"1" forKey:#"selected"];
[statusInitiationArray replaceObjectAtIndex:i withObject:statusDict];
}else {
[statusDict setValue:#"0" forKey:#"selected"];
[statusInitiationArray replaceObjectAtIndex:i withObject:statusDict];
}
}
NSLog(#"statusInitiationTable...%#",statusInitiationArray);
[statusInitiationTable.tableView reloadData];
[[self navigationController] pushViewController:statusInitiationTable animated:YES];
NSLog(#"ok");
}#catch (NSException * e) {
NSLog(#"statusInitiationButAction....%#",e);
}
}
Can anybody guide me about the problem.
Thanks
Amit Battan
You should not be doing this:
[tempArrIniId release];
Because in this line...
NSArray *tempArrIniId = [eventInitiationArray valueForKey:#"act_id"];
...you are not creating the tempArrIniId you are merely obtaining a reference to it. Therefore, you did not retain it and have no need to release it.
You are getting an intermittent crash because your over releasing the object pointed to by tempArrIniId while that object is still a member of the eventInitiationArray. When the array tries to access the object or even count itself, it crashes because there is not an object where it expects one to be. That crash can happen anywhere in the app where the 'eventInitiationArray' is used.
Overzealous releasing causes more problems than it prevents. When in doubt, don't release. It's trivial to find memory leaks with the analysis tools if you don't release something you should have and it's trivial to fix it.
It's a lot harder to track down a crash caused by over releasing an object held by other objects such as arrays because the subsequent crash can occur far from where the over release occurred.