I am retrieving phoneNumbers and I am getting a breakpoint. I've spent the past few hours trying to fix it, but still no luck.
-(void)textMessage{
ABAddressBookRef addressBook = ABAddressBookCreate();
NSMutableArray *array =[[NSMutableArray alloc]init];
NSMutableArray *temp;
NSMutableArray *temp2 = [[NSMutableArray alloc]init];
for(int i =0;i<[savedPeople count];i++){
NSString *temp = (NSString*) ABAddressBookCopyPeopleWithName(addressBook, (CFStringRef)[savedPeople objectAtIndex:i]);
NSLog(#"%#",temp);
[temp2 addObject:temp];
ABRecordRef thisPerson = (ABRecordRef)[temp2 objectAtIndex:i];
ABMultiValueRef phoneProperty = ABRecordCopyValue(thisPerson, kABPersonPhoneProperty);
NSLog(#"%#",phoneProperty);
}
array = temp2;
NSLog(#"%#",array);
CFRelease(addressBook);
}
![1] http://min.us/mQOzL3w5V
Anybody know what's wrong with it?
Breakpoints are somthing that you set, not errors. Go to the breakpoint inspector:
And delete any entries you find there. You can also turn off breakpoints temporarily with the Breakpoints button:
or via the menu command Product>Debug>Deactivate Breakpoints.
Related
I'm trying build an app that will work with iTunes. So, I imported the framework into my project and created a small class, just for learning purposes as follows:
-(NSMutableArray *)processMediaItems:(NSArray *)mediaItems {
NSMutableArray *titles = [NSMutableArray new];
if (mediaItems) {
for (ITLibMediaItem *item in mediaItems) {
[titles addObject:[item.title]];
}
}
return titles;
}
Then I decided to create a unit test for it, and did the following:
- (void)testExample {
ITLibMediaItem *mediaItem = [[ITLibMediaItem alloc] init];
//mediaItem.title = #"I Still Haven't Found What I'm Looking For";
NSMutableArray *mediaItems = [NSMutableArray new];
[mediaItems addObject:mediaItem];
MyClass *mc = [MyClass new];
NSMutableArray *titles = [mc processMediaItems:mediaItems];
}
The problem is that the property title is readonly.
So my question is, how do I create a new ITLibMediaItem object with a title? I tried to read the API (ITLibMediaItem) but didn't found a initialization that could help...
I find it. Properties in ITLibMediaItem are filled using setValuesForKeysWithDictionary:
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
[properties setObject:#"I Still Haven't Found What I'm Looking For" forKey:#"title"];
ITLibMediaItem *mediaItem = [[ITLibMediaItem alloc] init];
[mediaItem setValuesForKeysWithDictionary:properties];
NSMutableArray *mediaItems = [NSMutableArray new];
[mediaItems addObject:mediaItem];
I'm going to paste the code below, then tell you what I've tried to determine from the code.
If you're reading this quickly, start with the text right above the next code-block.
- (void)tableViewDidLoadModel:(UITableView*)tableView {
self.items = [NSMutableArray array];
self.sections = [NSMutableArray array];
NSMutableDictionary *groups = [NSMutableDictionary dictionary];
for (int c = 0;c < [_contacts.people count];c++) {
NSDictionary *person = [_contacts.people objectAtIndex:c];
NSString *name = [person objectForKey:#"fullName"];
NSString *letter = [name substringToIndex:1];
NSMutableArray *section = [groups objectForKey:letter];
NSLog(#"%# - %# - %#", name, [person objectForKey:#"index"], [person objectForKey:#"abId"]);
if (!section) {
section = [NSMutableArray array];
[groups setObject:section forKey:letter];
}
TTTableItem *item = [ttItem itemWithText:name URL:[person objectForKey:#"index"]];
[section addObject:item];
}
Someone else wrote this block of code. From what I can determine, they're trying to take the user's contacts and fill a TableView.
Now my real question has to do with that last line:
TTTableItem *item = [ttItem itemWithText:name URL:[person objectForKey:#"index"]];
[section addObject:item];
This is using the Three20 framework. Apparently what the previous developer did was use TTTableItem to kind of get a pre-formatted UITableViewCell. (Hopefully I'm thinking right?)
I need to replace this line of code with something normal.
I've thought of just using UITableViewCell, but other than that I'm not really sure how to start?
-tableViewDidLoadModel: is a method that comes from the TTTableViewDataSource protocol, so if you're trying to remove Three20 from your project, you've got more to do than just replace the TTTableItem.
TTTableItem is a subclass of NSObject, and the only thing it seems to add is a userInfo property. To get rid of it, you could start by creating your own class with the same property.
I'm attempting to complete the Stanford iPhone Programming (FA10) assignement "Flickr Fetcher" -- so far things are going well, however I have come to an impasse:
I have successfully extracted the location of the "Top 100" pictures, which are formated in a string as "Country, State, City". I would like to create two NSStrings -- one being the country, the other string being the State and City. From where I can then do
cell.textLabel.text = countryString;
cell.detailTextLabel.text = stateCityString;
in my table view datasource methods.
From research on stackoverflow and the Apple Documentaion, NSScanner seems to be my best bet -- here is what I have so far...
- (void)viewDidLoad {
//Get the top 100 photos from Flickr
self.topPlacesArray = [FlickrFetcher topPlaces];
NSString *mainLabelString = [[NSString alloc] init];
NSString *stringFromArray = [[NSString alloc] init];
//This retrieves the string of the location of each photo
stringFromArray = [topPlacesArray valueForKey:#"_content"];
NSScanner *theScanner = [NSScanner scannerWithString:stringFromArray];
NSCharacterSet *commaSet = [[NSCharacterSet alloc] init];
commaSet = [NSCharacterSet characterSetWithCharactersInString:#","];
while ([theScanner isAtEnd] == NO) {
if ([theScanner scanUpToCharactersFromSet:commaSet intoString:&stringFromArray]) {
NSLog(#"%#",stringFromArray);
}
}
I'm just trying to see if the string properly substrings itself -- however I am getting a "SIGBART" at the beggining of the while loop, the error is this:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI length]: unrecognized selector sent to instance 0x8939eb0'
From all the documentation I have seen on NSScanner, it seems I have it set up properly, however, no matter what changes I do, it seems unable to even begin the loop.
What do I have to do to set up NSScanner properly, to avoid the "SIGABRT"? (for the record, i'm assuming "SIGABRT" is a segfault?). Thank you all for your time, you all are the best!
(Btw: I know this is not fully implemented yet for both country and state-city, i just want to get used to NSScanner, I will implement the rest once I get NSScanner under control)
EDIT 1: SosBorn! You are incredible! Thank you so much! So I have implemented this for my viewDidLoad:
- (void)viewDidLoad
{
self.topPlacesArray = [FlickrFetcher topPlaces];
NSArray *ArrayOfStrings = [[NSArray alloc] init];
NSArray *placeElements = [[NSArray alloc] init];
NSString *country = [[NSString alloc] init];
NSString *city = [[NSString alloc] init];
NSString *state = [[NSString alloc] init];
ArrayOfStrings = [topPlacesArray valueForKey:#"_content"];
for (NSString *place in ArrayOfStrings) {
placeElements = [place componentsSeparatedByString:#", "];
if ([placeElements count] == 3 && [placeElements objectAtIndex:0] != nil) {
city = [placeElements objectAtIndex:0];
[self.cityArray addObject:city];
state = [placeElements objectAtIndex:1];
[self.stateArray addObject:state];
country = [placeElements objectAtIndex:2];
[self.countryArray addObject:country];
NSLog(#"%#, %#, %#", city, state, country);
}
else {
NSLog(#"Did this work?");
}
}
[ArrayOfStrings release];
[placeElements release];
[country release];
[city release];
[state release];
[super viewDidLoad];
}
This worked like a complete charm BUT i'm having some bad access going on in the Delegate when trying to access self.window.rootViewController = self.viewController -- this doesn't make any-sense (i actually have a completely empty table, etc...) -- so i'm thinking I played with bad memory management with my substring-ing and now it gets in trouble with this delegate call.
Chuck, I was very interested in your comment as I was taught that the proper way to make variables is to call [myclass alloc] init]; and then release when you are done -- as I have. Of course my objective-C greenness is showing a bit... blush.
You all and this incredible community are such an asset to us Students -- thank you for all your time and dedication. The only path to progress is a path of cooperation!
EDIT 2: Ok -- now it's totally fixed with no terrible leaking problems. Chuck you were right! I had the pricniples of alloc init completely mixed up in my head -- here was my final solution:
NSMutableArray *array1 = [[NSMutableArray alloc] init];
NSMutableArray *array2 = [[NSMutableArray alloc] init];
NSMutableArray *array3 = [[NSMutableArray alloc] init];
self.cityArray = array1;
self.countryArray = array2;
self.stateArray = array3;
[array1 release];
[array2 release];
[array3 release];
NSArray *ArrayOfStrings = [topPlacesArray valueForKey:#"_content"];
NSArray *topPlaces = [NSArray arrayWithArray:ArrayOfStrings];
NSArray *topPlacesSorted = [topPlaces sortedArrayUsingSelector:#selector(compare:)];
ArrayOfStrings = topPlacesSorted;
for (NSString *place in ArrayOfStrings) {
NSArray *placeElements = [place componentsSeparatedByString:#", "];
if ([placeElements count] == 3 && [placeElements objectAtIndex:0] != nil) {
NSString *city = [placeElements objectAtIndex:0];
[self.cityArray addObject:city];
NSString *state = [placeElements objectAtIndex:1];
[self.stateArray addObject:state];
NSString *country = [placeElements objectAtIndex:2];
NSString *stateAndCountry = [NSString stringWithFormat:#"%#, %#", state, country];
[self.countryArray addObject:stateAndCountry];
NSLog(#"%#, %#, %#", city, state, country);
}
else {
NSLog(#"Nil Request");
}
Thank you again SosBorn, i was feeling like I had forgotten the basics of CS ಠ_ಠ.
The only thing that really bothers me is why do we have to initialize instance NSMutableArrays that way -- i found this was the only way to get them to actually work.
Not totally sure why it is crashing, but I think another approach to this would serve you better. You have a topPlacesArray, why not iterate through the array and process each array entry seperately? I am making some assumptions about the topPlacesArray, but it would look something like this:
for (NSString *place in topPlacesArray)
{
//Place is probably in this format: "Country, State, City"
NSArray *placeElements = [place componentsSeperatedByString:#","];
//This should give you an array with three elements. Country State and city.
NSString *country = [placeElements objectAtIndex:0];
NSString *cityState = [NSString stringWithFormat:#"%#, %#", country, cityState];
//Now you have your strings that you need. Do whatever you need to do with them.
//Add them to an array or set the value of a text label, etc.
}
Didn't take the time to handle memory management but you get the idea.
The basic structure of my program has the user select an item from a UITableView, which corresponds to a stored text file. The file is then read into an array and a dictionary, where the array has the keys (I know I can just get the keys from the dictionary itself, this isn't my question).
The view is then changed to a UISplitView where the master view has the keys, and the detail view has the items in the dictionary attributed to that key. In this case, it's a series of "Yes/No" questions that the user selects the answer to.
My problem is this: When I click on a cell in the UITableView (first screen), it works fine, the data is read in perfectly, and so on. When I go back to the UITableView and click on the same cell again, the program crashes. Here is the read-in-from-file method:
-(NSArray *)readFromFile:(NSString *)filePath{
// NSLog(#"Path was: %#", filePath);
NSString *file = [[NSString alloc] initWithContentsOfFile:filePath];
// NSLog(#"File was: %#", file);
NSScanner *fileScanner = [[NSScanner alloc] initWithString:file];
NSString *held;
NSString *key;
NSMutableArray *detailStrings;
NSMutableArray *keys = [[NSMutableArray alloc] init];
NSMutableDictionary *details = [[NSMutableDictionary alloc] init];
/**
This is where the fun stuff happens!
**/
while(![fileScanner isAtEnd]){
//Scan the string into held
[fileScanner scanUpToString:#"\r" intoString:&held];
NSLog(#"Inside the while loop");
// If it is a character, it's one of the Key points, so we do the management necessary
if ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:[[held lowercaseString] characterAtIndex: 0]]){
NSArray *checkers = [[NSArray alloc] initWithArray:[held componentsSeparatedByString:#"\t"]];
NSLog(#"Word at index 2: %#", [checkers objectAtIndex:2]);
if(detailStrings != nil){
[details setObject:detailStrings forKey:key];
[detailStrings release];
}
NSLog(#"After if statement");
key = [checkers objectAtIndex:2];
[keys addObject:(NSString *) key];
detailStrings = [[NSMutableArray alloc] init];
}
else if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[[held lowercaseString] characterAtIndex: 0]]){
NSArray *checkers = [[NSArray alloc] initWithArray:[held componentsSeparatedByString:#"\t"]];
NSLog(#"Word at index 1: %#", [checkers objectAtIndex:1]);
[detailStrings addObject:[checkers objectAtIndex:1]];
}
}
NSLog(#"File has been read in");
[details setObject:detailStrings forKey:key];
NSArray *contents = [[NSArray alloc] initWithObjects:(NSMutableArray *) keys, (NSMutableDictionary *) details, nil];
[detailStrings release];
return contents;
}
I've determined that the program crashes inside the
if(detailStrings != nil)
statement. I figure this is because I'm missing some memory management that I am supposed to be doing, but don't have the knowledge of where it's going wrong. Any ideas as to the problem, or why it is crashing without giving me a log?
detailStrings is not initialized when you enter the while loop. When you declare NSMutableArray *detailStrings; inside a method, detailStrings is not automatically set to nil. So when you do
if ( detailStrings != nil ) { .. }
it enters the if statement and since it is not initialized, it will crash when you access detailStrings.
Another thing is that detailStrings won't be initialized if it enters the else part of the loop first. That will cause a crash too. So based on your requirement, either do
NSMutableArray *detailStrings = nil;
or initialize it before you enter the while loop.
Deepak said truth. You should initialize detailStrings with nil first.
But there is second possible issue:
I recommend also to set nil after release, because in the next loop you may test nonexistent part of memory with nil.
if(detailStrings != nil){
[details setObject:detailStrings forKey:key];
[detailStrings release];
detailStrings = nil;
}
And the third possible issue: depending from incoming data you may go to the second part of IF statement first time and try to addObject into non-initialized array.
The fourth (hope last): you have memory leak with "checkers" arrays
Here's what I'm seeing:
//read in the file
NSString *file = [[NSString alloc] initWithContentsOfFile:filePath];
//create the scanner
NSScanner *fileScanner = [[NSScanner alloc] initWithString:file];
//declare some uninitialized stuff
NSString *held;
NSString *key;
NSMutableArray *detailStrings;
//initialize some stuff
NSMutableArray *keys = [[NSMutableArray alloc] init];
NSMutableDictionary *details = [[NSMutableDictionary alloc] init];
//begin loop
while(![fileScanner isAtEnd]){
//scan up to a newline
[fileScanner scanUpToString:#"\r" intoString:&held];
//see if you scanned a lowercase string
if ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:[[held lowercaseString] characterAtIndex: 0]]){
//make an array
NSArray *checkers = [[NSArray alloc] initWithArray:[held componentsSeparatedByString:#"\t"]];
//do a check... against an uninitialized value
if(detailStrings != nil){
//set a potentially uninitialized value into an array with an uninitialized key
[details setObject:detailStrings forKey:key];
At this point, you're pretty much hosed.
The fix:
properly initialize your variables
run the static analyzer
read the memory management programming guide
I am not a Cocoa developer, but I have been dabbling in it to build some plugins for PhoneGap. This particular plugin method is either 1) crashing the app without saying why or 2) complaining about how I release/don't release an object. I have tried a ton of things on my end, including using an Enumerator instead of the for loop. If anyone can point me in the right direction, that would be awesome. I don't mind legwork:
- (void)getPreferences:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
NSUInteger argc = [arguments count];
NSString* jsCallback = nil;
if (argc > 0) {
jsCallback = [arguments objectAtIndex:0];
} else {
NSLog(#"Preferences.getPreferences: Missing 1st parameter.");
return;
}
NSDictionary *defaults = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
NSMutableArray *keys = (NSMutableArray *) [options objectForKey:#"keys"];
NSMutableDictionary *values = [[NSMutableDictionary alloc] init];
NSUInteger ky = [keys count];
for (int i = 0; i < ky; i ++) {
#try {
[values setObject:[defaults objectForKey:[keys objectAtIndex:i]] forKey:[keys objectAtIndex:i]];
}
#catch (NSException * err) {
NSLog(#"Error %#", err);
}
}
[keys release];
NSString* jsString = [[NSString alloc] initWithFormat:#"%#(%#);", jsCallback, [values JSONRepresentation]];
[defaults release];
[values release];
[webView stringByEvaluatingJavaScriptFromString:jsString];
[jsString release];
}
Human version:
options contains a dictionary with a single key of "keys"
that key contains an array of strings (that are going to be used as keys for lookup)
I want to loop through that array and
For every value that exists in defaults for that key, copy it to values using the same key
Finally, I want to send that values back as JSON (This part was working when I just passed the entire defaults object in, so I think the JSON method is working)
From your code, it follows that you 'own' objects values and jsString (the ones you created with alloc), so you should release them and not any other.
You can read more on memory management here.
Is this the whole code? Also, what exactly error do you get?
Nikita is right, it looks as though you're overreleasing defaults, which would cause a crash later when the autorelease pool gets released. Also, if I understand what you're trying to do correctly, you could create the values dictionary with a single line of code:
NSDictionary *values = [defaultsDict dictionaryWithValuesForKeys:keys];