kABPersonFirstNameProperty... trowing EXC_BAD_ACCESS - iphone

Im reading the address book contacts... everything goes well until I test a contact with no
First Name ( Since I can create a contact with just an email or a phone or wathever....).
The code (reduced) is this:
- (NSMutableArray *) getContactsInfo {
NSMutableArray *contactsList = [[NSMutableArray alloc] init];
localAddressBook = ABAddressBookCreate();
int contactsLength = (int)ABAddressBookGetPersonCount(localAddressBook);
if (contactsLength < 1)
return nil;
for(int currentContact=1; currentContact < (contactsLength + 1); currentContact++) {
ABRecordRef person = ABAddressBookGetPersonWithRecordID(localAddressBook,(ABRecordID) currentContact);
firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSLog(#"%#", firstName);
[contactsList addObject:firstName];
CFRelease(person);
}
return contactsList;
}
and the output I get is this:
2010-02-15 14:16:25.616 testApp[7065:207] Contact0
2010-02-15 14:16:25.618 testApp[7065:207] Contact1
2010-02-15 14:16:25.619 testApp[7065:207] Contact2
Program received signal: “EXC_BAD_ACCESS”.
I have 3 contacts with First and Last names
And one created with just the last name, for test purposes.
It seems I can properly read any property such as email or address with arrays... but when a contact lacks First Name Property the app crashes.

You are doing something very wrong in your code: you are assuming that the record IDs are sequential and starting at 1. This is not the case at all, you cannot rely on this.
What you should do instead is use ABAddressBookCopyArrayOfAllPeople to find all records in the Address Book and then use the Core Foundation CFArray functions to get to the individual items.
(Yes, the Address Book API in the iPhone is terrible)

You may want to enable NSZombies to see exactly where the EXEC_BAD_ACCESS is coming from.

To make sure, the crash is taking place within ABRecordCopyValue and not when you try to use firstName for the first time (which may be NULL?) Also, person is not NULL either, correct? (In general more code in the question along with details about which line is crashing would be helpful.)
Another thing to try would be to cast person to an ABRecord* and use [valueForProperty][1]; the two types are toll-free bridged and you might get a different result out of the latter (though I doubt it).
Update: Given the code you have posted you need to check that firstName is not NULL before trying to output it via NSLog - it is very possible ABRecordCopyValue is simply returning NULL (representing the fact there is no first name data present for that record.) You should also check for the validity of the person ref value itself - passing NULL in person to ABRecordCopyValue could be the source of additional problems.

The problem is indeed a nil first name - but not at the log statement, rather where you try to insert nil into the array. You cannot insert a nil value into an array, that causes a crash. NSLog has not flushed output to the console yet which is why you do not yet see your last log statement saying first name is nil.
Any time you get data out of the address book, check to see if the value is nil before you insert it into anything.

Related

Bugg with NSDictonary sometimes crashes with "Trying to insert nil" response

I´m having a great deal of trouble with a bugg that in some cases gives the "initWithObjects:forKeys:count:]: attempt to insert nil object from objects[6]'" error message. It´s only occurring around every third trial and in the other cases it works fine. I haven´t debugged buggs that happeds at certain situations so that´s whyI´m asking for help. It might be difficult to find a solution but I would be glad to receive some advice atleast where to start look for the issue and how to debug it?
Basically my app have a method that sends a NSDictonary list with objects to a server. In some cases I want to remove an object if the user have´t chosen anything for that list. Problem is that the server died´t like sending an object with an empty space. So I made a kind of not nice looking work around. Basically The IBaction checks if the Object contains nil. If it contains nil it redirects to a very similar NSDictonary without the Object containing Nil. It woks in some cases but it seems like it sometimes don´t recognize the object containing nil.
Here´s the code in Inaction that redirects the code. I haven´t created a method for inserting anything to the object:#"DefaultCreateImageID" yet so as far as I know it should always be nil.
NSString *Imagestuff= [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"];
if ( [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"] != ( NSString *) [NSNull null] ){
DataHandler *handler = [DataHandler sharedDatahandler];
handler.authenticateUserDelegate = self;
[handler createActivityNoImage];
NSLog(Imagestuff);
}
else
{
DataHandler *handler = [DataHandler sharedDatahandler];
handler.authenticateUserDelegate = self;
[handler createActivity];
}
Thanks!
If you get an error "Trying to insert nil" then one of the objects you are trying to add to the dictionary is nil. Solution: Don't do that.
Figure out why some item you are trying to add to the dictionary is nil. Then figure out what you want to do in the situation.
To follow up on gnashers729 answer. The problem for me isn't nil but the fact my Inaction fails to reqognize what the object contains.
Here for example I tried to replace nil with a string to reqognize. I get the same problem that my method in some cases recognize the string and in some cases don´t.
NSString *Imagestuff= [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"];
if ( [[NSUserDefaults standardUserDefaults] objectForKey:#"DefaultcreateImageID"] != ( NSString *) #"noImage" ){

App crashes when adding names to UIPickerView

When I click a button, a UIAlertView prompts the user to type a name. This name is then created as a new 'Customer' object and inserted into a mutable array.
There is a separate mutable array called 'CustListByName', which stores a list of all names.
The problem im having is that when adding a second or third name, the app crashes. Sometimes it happens on the second try, other times on the third try. There is no information given in the debugger except for (lldb). The program reports EXC_BAD_ACCESS and then it dumps me to a screen with a bunch of assembly code.
The crash is happening in these lines of code:
Essentially, it clears the array of names and then repopulates it based upon the object array. I've studied in step by step with a breakpoint but everything seems correct up until the point of crash. It is also confusing why this happens on the second or third try, never the first.
[custListByName removeAllObjects];
for (Customer *object in custListByObject) {
[custListByName addObject:object->name];
}
Here is the code where a customer is created and inserted everytime the new customer button is clicked:
Customer *tempCust = [[Customer alloc] init];
tempCust->name =[[alertView textFieldAtIndex:0] text];
[custListByObject addObject:tempCust];
[tempCust release];
I would really appreciate help with this, thanks!
What I suspect is happening is that the UIPickerView is attempting to load a row using information from your customer array after you have already cleared it, and before you repopulate it. This would cause a bad access error.
What you may consider doing instead, is keeping two arrays, an NSMutableArray for loading the customers, and an NSArray as the actual data source for the UIPickerView. Then right before you reload the UIPickerView, you say:
dataSourceArray = [loadingArray copy];
[pickView reloadAllComponents];
Hopefully this helps.
Edit:
Here's what your updated code would look like if your loading array was called loadingCustListByName:
[loadingCustListByName removeAllObjects];
for (Customer *object in custListByObject) {
[loadingCustListByName addObject:object->name];
}
custListByName = [loadingCustListByName copy];
[pickView reloadAllComponents];
Doing this will ensure that the UIPickerView's datasource array always matches up with the number of rows it thinks it has.

iPhone - Xcode - Invalid CFArrayRef when searching Address Book for a symbol

I'm trying to filter contacts using a search bar each time a user enters a character. This works fine for regular characters, but when a symbol is entered like $ or ( for the first character, ABAddressBookCopyPeopleWithName returns an "Invalid CFArrayRef". I've searched a while for the solution and I can't seem to find anything. The code is below.
CFArrayRef filteredContacts = ABAddressBookCopyPeopleWithName(addressBook, (CFStringRef)searchText);
CFMutableArrayRef filteredContactsMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(filteredContacts), filteredContacts);
CFArraySortValues(filteredContactsMutable, CFRangeMake(0, CFArrayGetCount(filteredContactsMutable)), (CFComparatorFunction)ABPersonComparePeopleByName, (void*)sortOrdering);
contacts = (NSArray *)filteredContactsMutable;
CFRelease(filteredContacts);
I get an EXC_BAD_ACCESS on the second line where filteredContactsMutable is created using filteredContacts. When I debug it, filteredContacts is an Invalid CFArrayRef when a symbol is the first character. The native PeoplePicker created by Apple allows you to search a symbol as the first character, so I know it's possible.
Any input would be appreciated.
first you should not trigger too much OS calls when you start search. load all data once and store it into array then search. and the reason why it crashes it due to nil argument in it cz i thnk no such user name find. try with simple charectrs n tell me if this prblm still exists

Object is deallocated - why? where?

Ok, I spent the last 8 hours fighting with it - it just seems beyond me. Here's my complete (relevant) code:
- (void)updateUserDefaults
{
NSMutableDictionary *viewControllerDetails = [[NSMutableDictionary alloc] initWithCapacity:4];
[viewControllerDetails setObject:[NSNumber numberWithInt:OOVenueClassControllerType] forKey:#"classType"];
[viewControllerDetails setObject:self.searchTerm forKey:#"searchTerm"];
[viewControllerDetails setObject:self.searchLocation forKey:#"searchLocation"];
//----- the next two lines cause the problem
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
[viewControllerDetails setObject:res forKey:#"searchresults"];
//-----
NSMutableArray *viewControllersList = [NSMutableArray array] ;
[viewControllersList addObject:viewControllerDetails];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
//the following line causes the error
[defs setObject:viewControllersList forKey:kViewControllersKey];
[defs synchronize];
[res release];
}
Note the block with the next two lines cause the problem. At first I didn't create another string, but added it later while trying to solve the problem.
If I comment out those two lines, everything works fine. If I put them back in, I get
- [CFString class]: message sent to deallocated instance 0xa1a9000
Is something is wrong with the string that I'm trying to put into the userdefaults? That string is rather large (about 200,000 characters), but I had stored even longer strings in user defaults in the past.
It's also worth noting that if I uninstall the app, then everything works fine. But on subsequent runs the problem exhibits itself.
So, how and why and where is the string getting deallocated? I have explicitly added retain - but that still doesn't help. What am I missing?
Edit: just realised I forgot to say that the error is thrown on line
[defs setObject:viewControllersList forKey:kViewControllersKey];
Also, for general information, method - (NSString *)xmlString on searchResults does exactly what the name means: creates an XML string with the information from that object.
Edit 2: I tried doing something else with that string - convert it to NSData, compress using zlib - but regardless of data type, that particular object gets deallocated. Does it have to do something with the size of the string?
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
Is auto released. You don't need to release it at the end of your method. You are over-releasing it.
Further, you don't need to retain the [searchResults xmlString]. The stringWithFormat method already does it for you.
Good Luck!
Ok, not sure what exactly the problem was, but it was somewhere in the searchResults and/or xmlString method. searchResults object is originally created from XML received from the server (XML is parsed into the object structure). When xmlString was called, for some reason the string I was getting back was different from the original XML (I'm not talking about formatting, of course) - of 200,000 char-long string, within the first 500 chars or so there were some differences. I haven't been able to figure out why. So, instead of recreating the xml from object structure, I instead stored the original XML in a field in that object and, when xmlString was called, simply returned the original string. Now everything worked fine.
Thank you all for your support through this painful process.

Address Book propertyID - unknown type?

Working on an app that makes heavy use of the Address Book framework. There are a number of View Controllers that interact with Address Book data, and they all work just fine. Except for one, and it's killing me.
I have a class that wraps address book access, in a method such as:
- (NSDictionary*)labelsToValues:(ABPropertyID)propertyID {
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef aRecord = ABAddressBookGetPersonWithRecordID(addressBook, [self recordIdFromAddressBookId]);
NSMutableDictionary *entries = [NSMutableDictionary dictionary];
ABMultiValueRef multiValueProperty = ABRecordCopyValue(aRecord, propertyID);
// do some other stuff
And then I call it in places like this:
- (NSDictionary*)emailProperties {
return [self labelsToValues:kABPersonEmailProperty];
}
And it works! Of course it does, I'm sending the message with an argument that is a Constant from the Address Book framework. So it should always work!
But that's not the case. This particular emailProperties: message is one that I'm calling in several places... and sometimes it works, but sometimes it doesn't. When things go awry, I put it through the debugger and I get something like this:
How is that possible!? Even odder, if I sort of "prime" the problematic View Controller by viewing other View Controllers where everything behaves as expected, and then I return to the problematic View Controller, everything works fine. So, I'm guessing this is some sort of linking error, but I'm not sure how to even begin with troubleshooting that.
Turns out my question was a dupe of Address Book constants evaluating as zero, please vote to close.