I'm quite frustrated with an issue I'm experiencing that Is coming with a lack of information. I'm unable to locate any information regarding my issue and I'm starting to believe It isn't possible what I want to do. Here is my issue and thank you for reading.
I would like for a button on my ViewController to open Apple Maps from Longitude and Latitude coordinates that are stored in my Sqlite database Tables. I have been able to successfully do this by adding a MapView. I want to reproduce this function and have the user be able to click "Get Directions" button and It will popup the Apple Maps app with the end address setup automatically. By using #"finishLat" and #"finishLng" I'm able to collect the database information. Is this possible when using the Apple URL Scheme?
This is a sample of what the Mapview does with the information. The only part I want from this is the #"finishLat" and #"finishLng". I will also need to use the "Run" feature as well to collect the correct address.
[super viewDidLoad];
CGRect bounds = self.view.bounds;
mapview = [[MapView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height)];
[self.view addSubview:mapview];
NSArray *result = [_runs objectForKey:#"results"];
NSDictionary *arr = [result objectAtIndex:0];
arr = [arr objectForKey:#"run"];
NSMutableArray *arrPlaces = [[NSMutableArray alloc] init];
NSArray *arrDirvers = [arr objectForKey:#"drivers"];
for (int i =0; i < [arrDirvers count]; i++) {
NSDictionary *asdfg = [arrDirvers objectAtIndex:i];
Place *startPt = [[Place alloc] init];
Place *endPt = [[Place alloc] init];
NSString *temp = [asdfg objectForKey:#"startLat"];
startPt.latitude = [temp floatValue];
temp = [asdfg objectForKey:#"startLng"];
startPt.longitude = [temp floatValue];
startPt.name = [asdfg objectForKey:#"name"];
temp = [asdfg objectForKey:#"finishLat"];
endPt.latitude = [temp floatValue];
temp = [asdfg objectForKey:#"finishLng"];
endPt.longitude = [temp floatValue];
endPt.name = [asdfg objectForKey:#"name"];
[arrPlaces addObject:startPt];
[arrPlaces addObject:endPt];
This is what I have.
- (IBAction)GetDirections:(id)sender {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: #"http://maps.apple.com/?q"]];
}
Rather than using openURL: you can create an instance of MKMapItem and use openInMapsWithLaunchOptions:. You can supply the MKLaunchOptionsDirectionsModeKey option to request directions from the users current location.
Alternatively, use openMapsWithItems:launchOptions: to navigate between 2 known locations.
To open in the Apple Maps app use:
- (IBAction)GetDirections:(id)sender
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: #"http://maps.apple.com/?ll=<lattitude>,<longitude>"]];
}
If you want to open Apple Maps to a driving directions screen, you will need to use this url:
http://maps.apple.com/?saddr=<origin>&daddr=<destination>
You can also set one of these to be "Current%20Location" to use the user's current location.
Related
I want to open my latitude and longitude values with modified markers and with details. So that I need to check if google map app installed I need to open with that else I will navigate into apple map.
Here I couldn't add custom pin with following code,
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"maps.apple.com/?z=12&q=%f,%f",[latitude floatValue],[longitude floatValue]]];
if (![[UIApplication sharedApplication] canOpenURL:url]) {
NSLog(#"Google Maps app is not installed");
//left as an exercise for the reader: open the Google Maps mobile website instead!
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:rdOfficeLocation addressDictionary:nil];
MKMapItem *item = [[MKMapItem alloc] initWithPlacemark:placemark];
item.name = [NSString stringWithFormat:#"%#",[[mDataArray1 objectAtIndex:indexPath.row] valueForKey:#"NAME"]];
item.phoneNumber = [NSString stringWithFormat:#"%#",[[mDataArray1 objectAtIndex:indexPath.row] valueForKey:#"DESTINATION"]];
[item openInMapsWithLaunchOptions:nil];
} else {
[[UIApplication sharedApplication] openURL:url];
}
So please help me to add custom pin values for both apple and google maps.
You can look at how to add a custom marker in the official documentation. However, this will only work for Google Maps and not Apple Maps (in which case you'll need a different library for it)
I'm making app with section tableview.The section header display district through keyArray. To row of table view, it will display all information including of name, address and distance. I can make it by below code.
Now, I'm going to sort ascending distance in tableview.
How can I sort it in 'cellForRowAtIndexPath' method?
My second thought is create NSArray at the outside of cellForRowAtIndexPath method. One is to load plist data and calculate distance. And then, sort it through NSSortDescriptor. If I go to this method, I am not sure how to populate it in section tableview correctly?
Can someone give me some idea or suggestion?
In key array, I use below code to create it in ViewDidLoad and put it into section header.
//location info draw from plist
NSArray*tempArray=[[NSArray alloc]init];
tempArray=[dataDictionary allKeys];
self.keyArray=[tempArray mutableCopy];
In cellForRowAtIndexPath, it calculate distance between target location and user location. And then display all information in table view row.
NSString*sectionHeader=[keyArray objectAtIndex:indexPath.section];
NSArray*sectionHeaderArray=[dataDictionary objectForKey:sectionHeader];
NSDictionary*targetLat=[sectionHeaderArray objectAtIndex:indexPath.row];
NSDictionary*targetLong=[sectionHeaderArray objectAtIndex:indexPath.row];
//location info draw from plist
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:[[targetLat objectForKey:#"latitude"] floatValue] longitude:[[targetLong objectForKey:#"longitude"] floatValue]];
double distance = [self.myLocation distanceFromLocation:targetLocation]/1000;
UITableViewCell*cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier] autorelease];
}
UILabel*nameLabel=(UILabel*)[cell viewWithTag:100];
UILabel*addLabel=(UILabel*)[cell viewWithTag:101];
UILabel*latLabel1=(UILabel*)[cell viewWithTag:102];
UILabel*longLabel1=(UILabel*)[cell viewWithTag:103];
UILabel*disLabel=(UILabel*)[cell viewWithTag:106];
NSDictionary*name=[sectionHeaderArray objectAtIndex:indexPath.row];
NSDictionary*address=[sectionHeaderArray objectAtIndex:indexPath.row];
nameLabel.text=[name objectForKey:#"name"];
addrLabel.text=[address objectForKey:#"address"];
latLabel1.text=[NSString stringWithFormat:#"%f",self.myLocation.coordinate.latitude];
longLabel1.text=[NSString stringWithFormat:#"%f",self.myLocation.coordinate.longitude];
disLabel.text=[NSString stringWithFormat:#"%0.2f km",distance];
return cell;
}
I jumped to conclusions and posted an answer that was flawed. I see now that you have a multitude of issues in your process.
You assign the same object, [sectionHeaderArray objectAtIndex:indexPath.row], to several different variables and are expecting different results from each. To start with, I would make the following changes to your existing code:
NSString*sectionHeader=[keyArray objectAtIndex:indexPath.section];
NSArray *locationsForSection = [self.dataDictionary objectForKey:sectionHeader];
NSDictionary *thisLocationInfo = [locationsForSection objectAtIndex:indexPath.row];
float thisLat = [[thisLocationInfo objectForKey:#"latitude"] floatValue];
float thisLong = [[thisLocationInfo objectForKey:#"longitude"] floatValue];
//location info draw from plist
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:thisLat longitude:thisLong];
double distance = [self.myLocation distanceFromLocation:targetLocation]/1000;
UITableViewCell*cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier];
}
UILabel*nameLabel=(UILabel*)[cell viewWithTag:100];
UILabel*addLabel=(UILabel*)[cell viewWithTag:101];
UILabel*latLabel1=(UILabel*)[cell viewWithTag:102];
UILabel*longLabel1=(UILabel*)[cell viewWithTag:103];
UILabel*disLabel=(UILabel*)[cell viewWithTag:106];
NSDictionary*name=[sectionHeaderArray objectAtIndex:indexPath.row];
NSDictionary*address=[sectionHeaderArray objectAtIndex:indexPath.row];
latLabel1.text=[NSString stringWithFormat:#"%f",thisLat];
longLabel1.text=[NSString stringWithFormat:#"%f",thisLong];
disLabel.text=[NSString stringWithFormat:#"%0.2f km",distance];
return cell;
}
For your sorting issue, I would say to go back to your dataDictionary. Iterate through each of the sectionHeader arrays. Replace each array with a copy that is sorted by the distance from myLocation. You could add the key, distance, to each dictionary there and take that out of the cellForRowAtIndexPath method entirely.
-(NSDictionary *)dataDictionary
{
if (_dataDictionary) {
return _dataDictionary;
}
NSMutableDictionary *resultDictionary = [[NSMutableDictionary alloc] init];
for (NSString *sectionHead in self.keyArray) {
NSMutableArray *sectionArrayWithDistances = [[NSMutableArray alloc] init];
NSArray *thisSectionArray = [sourceDictionary objectForKey:sectionHead];
for (NSDictionary *theLocationDict in thisSectionArray) {
// Calculate the distance
float thisLat = [[theLocationDict objectForKey:#"latitude"] floatValue];
float thisLong = [[theLocationDict objectForKey:#"longitude"] floatValue];
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:thisLat longitude:thisLong];
double distance = [self.myLocation distanceFromLocation:targetLocation]/1000;
// Insert modified dictionary into the resulting section array
NSMutableDictionary *thisLocationWithDistance = [NSMutableDictionary dictionaryWithDictionary:theLocationDict];
[thisLocationWithDistance insertObject:[NSNumber numberWithDouble:distance] ForKey:#"distance"];
[sectionArrayWithDistances addObject:[NSDictionary dictionaryWithDictionary:thisLocationWithDistance]];
}
// Sort the resulting array for this section and insert in dataDict
NSSortDescriptor *sortByDistance = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortByDistance, nil];
[sectionArrayWithDistances sortWithDescriptors:sortDescriptors];
[resultDictionary insertObject:[NSArray arrayWithArray:sectionArrayWithDistances] forKey:sectionHead];
}
// Set result and return
self.dataDictionary = [NSDictionary dictionaryWithDictionary:resultDictionary];
return _dataDictionary;
}
Total Air Code and turned out to be more than I bargained for. Possible errors in syntax and what not but this is the basic idea as I see it for your purposes.
I'm a bit confused by the documentation. After some research and experimentation, this is what I have.
if ([self canUseMKMapItem]) {
[self iosTheMap];
} else {
[self googleTheMap];
}
Using this to detect whether we can use the IOS6 mapping features:
- (BOOL) canUseMKMapItem {
Class itemClass = [MKMapItem class];
return (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]);
}
This for IOS5, using Google Maps. It automatically takes us to a screen with a list of directions from the current address (if the user allows) to the destination.
- (void)googleTheMap
{
NSNumber *userLat = [[NSNumber alloc]initWithDouble:mapView.userLocation.coordinate.latitude];
NSNumber *userLong = [[NSNumber alloc]initWithDouble:mapView.userLocation.coordinate.longitude];
NSMutableString *queryString = [NSMutableString stringWithFormat:#"http://maps.google.com/?saddr=%#,%#&daddr=",userLat,userLong];
NSString *address = [partnerObject valueForKey:ATTRIBUTE_ADDRESS];
[queryString appendString:address];
NSString *escaped = [queryString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:escaped]];
}
Here's the tricky part--this is what I'm trying to do to use Apple Maps
- (void)iosTheMap {
NSNumber * latitude = [partnerObject valueForKey:ATTRIBUTE_LATITUDE];
NSNumber * longitude = [partnerObject valueForKey:ATTRIBUTE_LONGITUDE];
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;
NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];
[addressDictionary setValue:[partnerObject valueForKey:ATTRIBUTE_ADDRESS] forKey:kABPersonAddressStreetKey];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:addressDictionary];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem openInMapsWithLaunchOptions:nil];
}
This "works," sort of. It takes the user to a map screen with a pin showing the address. The user can tap that and get directions. However, I have a few reservations about this approach:
I have a compiler warning where I set kABPersonAddressStreetKey: "Incompatible pointer types sending 'const CFStringRef' (aka 'const struct __CFString *const') to parameter of type 'NSString *'"
The string value I am using is the full address. I use that value for the street address, although the address values are meant to be more atomic--street, city, state. It seems to work, but I'm concerned this isn't the right way to do it.
It would be nice if Apple Maps showed the name of the business/destination, not just the address.
It would be great to have Apple Maps automatically show the directions, instead of a map with the destination point, saving the user a few taps.
Any suggestions for how I can improve my approach? Although it seems to work, I suspect that it is not the right way.
You are pretty close. You need to specify the Launch Options dictionary for the openInMapsWithLaunchOptions function using the MKLaunchOptionsDirectionsModeDriving, MKLaunchOptionsDirectionsModeKey value and key.
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
// Use iOS 6 maps
CLLocationCoordinate2D coordinate = [((LocationAnnotation*)[map.annotations objectAtIndex:0]) coordinate];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem openInMapsWithLaunchOptions:[NSDictionary dictionaryWithObjectsAndKeys:MKLaunchOptionsDirectionsModeDriving, MKLaunchOptionsDirectionsModeKey, nil]];
} else {
//Fall back on google
...
}
Im working on a simple "point based" app.
under settings the user set´s the number of points needed to get a "goodie" using a slider.
-(IBAction) sliderChanged: (id)sender {
UISlider *slider = (UISlider *) sender;
int progressAsInt =(int)(slider.value +0.5);
NSString *newText = [[NSString alloc] initWithFormat:#"%d",progressAsInt];
sliderLabel.text = newText;
[newText release];
this works fine, but how so i store the slider value in my core data model, and how do make my slider show the stored value when view loads.
hope u can help me out :-D
Hey gerry3 i found my error. i never set my toD-object in my settingsViewController, with:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription
entityForName:#"ToDo" inManagedObjectContext:_context]];
NSError *error = nil;
NSArray *array = [_context executeFetchRequest:request error:&error];
if (array == nil)
{
// Deal with error...
}
if(array.count > 0){
toDo = [array objectAtIndex:0];
} else { // no one to fetch - generate one
toDo = [NSEntityDescription
insertNewObjectForEntityForName:#"ToDo"
inManagedObjectContext:_context];
[toDo retain];
your code works like a charm .....
Thanks
Skov
The key here is that Core Data stores numeric attributes (e.g. integers, floats, etc) as NSNumber objects.
Say that your entity is called Record and it has a integer attribute called 'progress'.
If you create a managed object instance of Record named 'record', then you can set its progress like this:
[record setValue:[NSNumber numberWithInteger:progressAsInt] forKey:#"progress"];
When you want to update your view with the value from your model (usually in viewWillAppear:), you can get its progress like this:
NSNumber *progressNumber = [record valueForKey:#"progress"];
slider.value = [progressNumber floatValue];
Alternatively, if you generate the class files for the Record entity, you can just do:
record.progress = [NSNumber numberWithInteger:progressAsInt];
and:
slider.value = [record.progress floatValue];
I've been working a product display app but it has a memory leak that causes it to crash after too many categories have been loaded up. The app works via a SplitViewController that lists the categories down the left and, once tapped, the product images show in the detailViewController on the right.
Selecting category after category eventually crashes the app.
I've used the instruments -> Leaks tool to trace the problem and I get told that NSString appendString is a leak. The number of strings leaked seems to match the number of products in the category selected so I'm guessing one of my loops holds the problem but, after playing around with AutoreleasePools I haven't solved it yet.
My code:
This method is called when the category is selected and parses an XML document
- (NSMutableArray*) processXML{
//NSAutoreleasePool *pool4 = [[NSAutoreleasePool alloc] init];
// Initialize the productEntries MutableArray declared in the header
products = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSMutableString *documentsDirectory = [[NSMutableString stringWithFormat:#"%#", [paths objectAtIndex: 0]] autorelease];
// paths to save inputs to
NSString *productsFile = [documentsDirectory stringByAppendingFormat: #"/products2.xml"];
NSData *data = [NSData dataWithContentsOfFile: productsFile];
// Create a new rssParser object based on the TouchXML "CXMLDocument" class, this is the object that actually grabs and processes the RSS data
NSError *error = nil;
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding options:0 error:&error] autorelease];
// Create a new Array object to be used with the looping of the results from the rssParser
NSArray *resultNodes = NULL;
//NSString *xPathStart, *xPathEnd, *category, *finalStr;
NSString *xPathStart = [[NSString stringWithFormat:#""] autorelease];
NSString *xPathEnd = [[NSString stringWithFormat:#""] autorelease];
NSString *category = [[NSString stringWithFormat:#""] autorelease];
NSString *finalStr = [[NSString stringWithFormat:#""] autorelease];
NSString *detailStr = [[NSString stringWithFormat: detailItem] autorelease];
// category to be parsed - build up xPath expression
if([detailStr isEqualToString: #"On Order Stock"]) {
xPathStart = #"/products/product[instock='2";
xPathEnd = #"']";
finalStr = [NSString stringWithFormat:#"%#%#", xPathStart, xPathEnd];
} else {
xPathStart = #"/products/product[category='";
category = detailItem;
xPathEnd = #"']";
finalStr = [NSString stringWithFormat:#"%#%#%#", xPathStart, category, xPathEnd];
}
resultNodes = [rssParser nodesForXPath: finalStr error:nil];
// Loop through the resultNodes to access each items actual data
for (CXMLElement *resultElement in resultNodes) {
Product *productItem = [[Product alloc] init];
[productItem setCode: [[[resultElement childAtIndex: 1] stringValue] autorelease]];
[productItem setImage: [[[resultElement childAtIndex: 5] stringValue] autorelease]];
// Add the product object to the global productEntries Array so that the view can access it.
[products addObject: productItem];
[productItem release];
}
//[pool4 release];
return products;
}
As you can see I went a little crazy with autoReealse on my strings. The other code segment that displays the images could be the problem although Leaks does mention processXML directly.
- (void) displayImages:(NSMutableArray *)anArray {
// create scrollView object
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 100)];
scrollView.pagingEnabled = NO;
scrollView.scrollEnabled = YES;
scrollView.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1];
scrollView.userInteractionEnabled = YES;
//create info area below scrollView
infoView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 100, self.view.frame.size.width, 100)];
[infoView setContentSize:CGSizeMake(self.view.frame.size.width, 100)];
infoView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
infoView.scrollEnabled = NO;
[barcodeImgView setImage:[UIImage imageNamed:#"barcode2.jpg"]];
[infoView addSubview:codeLbl];
[infoView addSubview:nameLbl];
[infoView addSubview:priceLbl];
[infoView addSubview:dimensionsLbl];
[infoView addSubview:stockLbl];
[infoView addSubview:commentsLbl];
[infoView addSubview:barcodeImgView];
infoView.userInteractionEnabled = YES;
[codeLbl setText:[[NSString stringWithFormat:#""] autorelease]];
[nameLbl setText:[[NSString stringWithFormat:#""] autorelease]];
[priceLbl setText:[[NSString stringWithFormat:#""] autorelease]];
[commentsLbl setText:[[NSString stringWithFormat:#""] autorelease]];
[stockLbl setText:[[NSString stringWithFormat:#""] autorelease]];
[dimensionsLbl setText:[[NSString stringWithFormat:#""] autorelease]];
// hold x and y of each image
int x = 30;
int y = 50;
int noOfImages = [anArray count];
int maxRowWidth = (noOfImages / 3) + 1;
int xcount = 0; // position across the row, reset to zero and drop image down when equal to (noOfImages / 3) + 1
//NSAutoreleasePool *displayPool = [[NSAutoreleasePool alloc] init];
for(int i = 0; i < noOfImages; i++) {
// declare Product object to hold items in anArray
Product *prod = [[Product alloc] init];
prod = [anArray objectAtIndex: i];
// try for image in Documents folder, later checks it exists and if not uses Resource location
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSMutableString *documentsDirectory = [[NSString stringWithFormat:#"%#", [paths objectAtIndex: 0]] autorelease];;
// paths to save inputs to
NSString *imgName = [[NSString stringWithFormat:#"%#/%#", documentsDirectory, [prod image]] autorelease];
NSString *productName = [[NSString stringWithFormat:#"%#", [prod code]] autorelease];
// create and size image
UIImage *image = [UIImage imageWithContentsOfFile: imgName];
// set up button
UIButton *button= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(imageButtonClick:) forControlEvents:(UIControlEvents)UIControlEventTouchDown];
[button setTitle:productName forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize: 0];
[button setTitleColor: [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1] forState: UIControlStateNormal];
CGSize imageSize = image.size;
CGFloat height = imageSize.height;
CGFloat width = imageSize.width;
CGFloat ratio = 160 / width; // get ratio to divide height by
UIGraphicsBeginImageContext(CGSizeMake((height * ratio),160));
CGContextRef context = UIGraphicsGetCurrentContext();
[image drawInRect: CGRectMake(0, 0, height * ratio, 160)];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// create frame for image
CGRect newFrame = CGRectMake(x, y, 160,160);
UILabel *codeLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, y - 20, 170, 20)];
codeLabel.text = productName;
codeLabel.textColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
codeLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1];
[button setFrame: newFrame];
[button setBackgroundImage:smallImage forState:UIControlStateNormal];
[scrollView setContentSize:CGSizeMake((maxRowWidth * 160) + 160,self.view.frame.size.height - 100)];
[self.scrollView addSubview:button];
[self.scrollView addSubview:codeLabel];
xcount++;
x = x + 170; // move across the page
if(xcount == maxRowWidth) {
y = y + 210; // move down the screen for the next row
x = 30; // reset x to left of screen
xcount = 0; // reset xcount;
}
[prod release];
}
//[displayPool release];
[self.view addSubview: scrollView];
[self.view addSubview: infoView];
[scrollView release];
[infoView release];
[pool release];
}
By the way, pool is an autoreleasePool defined in the h file for the class.
I would really appreciate any specific help regarding my code or general tips on what could be wrong.
I see a few things wrong:
As was mentioned in the comments, you're abusing -autorelease in ways which make grown men cry and that which will crash your app.
-processXML is returning an owned object. You're allocating products and returning it. This breaks convention, because the method name does not begin with new or alloc, and does not contain copy. You should return [products autorelease]; instead. However, even that is shady, because since products isn't declared locally, it's probably an instance variable. In that case, what happens if processXML gets invoked multiple times? You have an owned object referenced by the instance variable, and suddenly you overwrite that reference with a new one... = memory leak.
Every time someone does MyClass * object = [[MyClass alloc] init]; object = [something thatReturnsAMyClass];, a kitten dies. If you then do [object release];, a second dies for good measure. This is a terrible, terrible memory leak (and a likely crash). You're allocating a new object and then immediately throwing it away but never releasing it. That you do this suggests you don't really get what a pointer is. I suggest reading "Everything you need to know about pointers in C"
On a lighter note, you should check out -[NSString stringByAppendingPathComponent:]. NSString has a bunch of really nice methods for dealing with paths.
I hope I don't come off as too harsh. :)
Some while ago at another post somebody said that one should read about the memory management and I was actually thinking that this answer is not really right. What is wrong with some trial and error and learning by doing. But after I had my painful experiences with memory I must admit that this guy was right. Take the time. Go and read the chapter on memory management in the apple documentation.
As above stated already you should not autorelease an object you do not own. But this might not cause the trouble. You can next to the instruments use Build+Analyze in the Build menu. This will help you to find out more.
Basically you need to release objects you create which you own (which one you own is in the documentation, basically those created with "alloc" and some more). If you cannot release them you assign them to the autorelease pool. This is the case with the "products" you return from processXML. When is the autorelease pool drained? This is when the next time the framework of the application is back in control (I think it was called run-loop or something). This can be a while and so you should not open to much objects which are assigned to an autorelease pool.
So to help you really read that chapter: memory management programming guide