Я получаю довольно много утечек памяти с помощью цикла в моем методе - (void)connectionDidFinishLoading:(NSURLConnection *)connection
.Просто интересно, может ли кто-нибудь привести меня в правильном направлении относительно того, как уменьшить количество происходящих утечек памяти?Возможно, это не лучший код ... любая помощь в других областях будет принята с благодарностью.
// SearchViewController.h
#import <UIKit/UIKit.h>
#import "VenueDetailViewController.h"
#import "OverlayViewController.h"
#import "TBXML.h"
#import "CoreLocationController.h"
@interface SearchViewController : UIViewController <UITableViewDelegate, UISearchBarDelegate, CoreLocationControllerDelegate> {
VenueDetailViewController *venueDetailView;
IBOutlet UITableView *tv;
NSString *navBarTitle;
NSMutableArray *venues;
NSMutableArray *primaryCategories;
NSString *categoryId;
//Search properties.
OverlayViewController *overlayView;
IBOutlet UISearchBar *searchBar;
BOOL letUserSelectRow;
//Core location properties.
CoreLocationController *CLController;
BOOL searching;
NSMutableData *responseData;
}
@property (nonatomic, retain) NSString *navBarTitle;
@property (nonatomic, retain) CoreLocationController *CLController;
@property (nonatomic, retain) VenueDetailViewController *venueDetailView;
@property (nonatomic, retain) OverlayViewController *overlayView;
@property (nonatomic, retain) IBOutlet UITableView *tv;
@property (nonatomic, retain) NSMutableArray *venues;
@property (nonatomic, retain) NSMutableArray *primaryCategories;
@property (nonatomic, retain) NSString *categoryId;
- (void)doneSearching_Clicked:(id)sender;
- (void)findLocations:(id)sender;
- (void)loadPlacesWithLat:(NSString *)lat andLong:(NSString *)lng;
- (void)findPostcode:(NSString *)postcode;
- (void)showReloadButton;
@end
// SearchViewController.m
#import "SearchViewController.h"
#import "GenericCell.h"
#import "FSVenue.h"
#import "AsyncImageView.h"
#import "Helper.h"
#import "JSON.h"
@implementation SearchViewController
@synthesize tv;
@synthesize venueDetailView, overlayView;
@synthesize CLController;
@synthesize navBarTitle;
@synthesize venues, primaryCategories;
@synthesize categoryId;
- (void)viewDidLoad {
//Set the title.
navBarTitle = @"Nearby Places";
self.title = navBarTitle;
//Set background and border to clear (to allow for background image to be visible).
tv.backgroundColor = [UIColor clearColor];
[tv setSeparatorColor:[UIColor clearColor]];
//Add the search bar.
tv.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
letUserSelectRow = YES;
venues = [[NSMutableArray alloc] init];
primaryCategories = [[NSMutableArray alloc] init];
//Core location init.
CLController = [[CoreLocationController alloc] init];
CLController.delegate = self;
//Add a refresh icon to the top right navigation bar.
[self showReloadButton];
if (self.categoryId != nil) {
[self findLocations:nil];
}
searching = NO;
[super viewDidLoad];
}
- (void)showReloadButton {
UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:@selector(findLocations:)];
self.navigationItem.rightBarButtonItem = refreshItem;
[refreshItem release];
}
#pragma mark -
#pragma mark Nearby Places / Core Location
- (void)findLocations:(id)sender {
// Display loading overlay view.
if (!searching) {
[Helper beginLoading:self.view withTitle:navBarTitle];
[self doneSearching_Clicked:nil];
//Calls locationUpdate delegate method.
[CLController.locMgr startUpdatingLocation];
searching = YES;
}
}
- (void)locationUpdate:(CLLocation *)location {
NSString *lat;
NSString *lng;
#if !(TARGET_IPHONE_SIMULATOR)
lat = [NSString stringWithFormat:@"%f", location.coordinate.latitude];
lng = [NSString stringWithFormat:@"%f", location.coordinate.longitude];
#else
lat = @"-37.816016";
lng = @"144.969717";
#endif
[self loadPlacesWithLat:lat andLong:lng];
}
- (void)locationError:(NSError *)error {
NSLog(@"locationError: %@", [error description]);
}
- (void)loadPlacesWithLat:(NSString *)lat andLong:(NSString *)lng {
[CLController.locMgr stopUpdatingLocation];
responseData = [[NSMutableData data] retain];
NSString *url = [NSString stringWithFormat:@"https://api.foursquare.com/v1/venues.json?geolat=%@&geolong=%@", lat, lng];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)findPostcode:(NSString *)pcode {
//Webservice URL: http://ws.geonames.org/findNearbyPostalCodes?postalcode=2000&country=AU&style=SHORT&maxRows=1
NSString *suburb;
NSString *postcode;
NSString *lat1;
NSString *lng1;
// load and parse an xml string.
TBXML* tbxml = [[TBXML alloc] initWithURL:[NSURL URLWithString:
[NSString stringWithFormat:@"http://ws.geonames.org/findNearbyPostalCodes?postalcode=%@&country=AU&style=SHORT&maxRows=1",
pcode]]];
// obtain root element.
TBXMLElement *root = tbxml.rootXMLElement;
// if root element is valid.
if (root) {
// search for the first geonames element within the root elements children.
TBXMLElement *code = [TBXML childElementNamed:@"code" parentElement:root];
if (code != nil) {
// find the lat child element of the code element.
TBXMLElement *lat = [TBXML childElementNamed:@"lat" parentElement:code];
if (lat != nil) {
lat1 = [TBXML textForElement:lat];
}
// find the long child element of the code element.
TBXMLElement *lng = [TBXML childElementNamed:@"lng" parentElement:code];
if (lng != nil) {
lng1 = [TBXML textForElement:lng];
}
// find the postalcode child element of the code element.
TBXMLElement *postalcode = [TBXML childElementNamed:@"postalcode" parentElement:code];
if (postalcode != nil) {
postcode = [TBXML textForElement:postalcode];
}
// find the postalcode child element of the code element.
TBXMLElement *name = [TBXML childElementNamed:@"name" parentElement:code];
if (name != nil) {
suburb = [TBXML textForElement:name];
}
NSLog(@"Searching Postcode %@ (%@) ...", postcode, suburb);
NSLog(@" Lat - %@", lat1);
NSLog(@" Long - %@", lng1);
[self loadPlacesWithLat:lat1 andLong:lng1];
}
}
// release resources
[tbxml release];
}
#pragma mark -
#pragma mark JSON Over HTTP
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"connectin didFailWithError: %@", [error description]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
//[responseData release];
NSDictionary *dictionary = [responseString JSONValue];
[responseString release];
NSArray *venueArray = [[[dictionary valueForKeyPath:@"groups"] objectAtIndex:0] valueForKeyPath:@"venues"];
if ([dictionary valueForKeyPath:@"error"] != nil) {
[Helper displayAlertMessage:[dictionary valueForKeyPath:@"error"] withTitle:@"Foursquare"];
}
for (id result in venueArray) {
FSVenue *venue = [[FSVenue alloc] init];
venue.name = [result valueForKeyPath:@"name"];
venue.venueId = [result valueForKeyPath:@"id"];
venue.geoLat = [result valueForKeyPath:@"geolat"];
venue.geoLong = [result valueForKeyPath:@"geolong"];
NSDictionary *primaryCategoryDict = [result valueForKeyPath:@"primarycategory"];
FSPrimaryCategory *primaryCategory = [[FSPrimaryCategory alloc] init];
primaryCategory.iconUrl = [primaryCategoryDict valueForKeyPath:@"iconurl"];
primaryCategory.iconUrl = [primaryCategory.iconUrl stringByReplacingOccurrencesOfString:@".png" withString:@"_64.png"];
primaryCategory.nodeName = [primaryCategoryDict valueForKeyPath:@"nodename"];
primaryCategory.primaryCategoryId = [NSString stringWithFormat:@"%@", [primaryCategoryDict valueForKeyPath:@"id"]];
//Check if categories match the category selected from the FSCategory controllers.
if (self.categoryId != nil) {
if ([self.categoryId isEqualToString:primaryCategory.primaryCategoryId]) {
[venues addObject:venue];
[venue release];
[primaryCategories addObject:primaryCategory];
[primaryCategory release];
} else {
[venue release];
[primaryCategory release];
}
} else {
[venues addObject:venue];
[venue release];
[primaryCategories addObject:primaryCategory];
[primaryCategory release];
}
}
[tv reloadData];
//Hide loading overlay view.
[Helper finishLoading:navBarTitle];
searching = NO;
}
#pragma mark -
#pragma mark Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [venues count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"GenericCell";
GenericCell *cell = (GenericCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:nil options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[UITableViewCell class]]) {
cell = (GenericCell *)currentObject;
break;
}
}
} else {
AsyncImageView *oldImage = (AsyncImageView *)
[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
FSPrimaryCategory *primaryCategory = (FSPrimaryCategory *)[primaryCategories objectAtIndex:indexPath.row];
FSVenue *venue = (FSVenue *)[venues objectAtIndex:indexPath.row];
AsyncImageView *asyncImage = [[[AsyncImageView alloc] initWithFrame:CGRectMake(3, 3, 48, 48)] autorelease];
asyncImage.tag = 999;
NSURL *url = [NSURL URLWithString:primaryCategory.iconUrl];
[asyncImage loadImageFromURL:url];
[cell.contentView addSubview:asyncImage];
//The two images are 1x140 vertical gradients that UIKit automatically stretches horizontally to fit the width of the cell.
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Cell_1x140.png"]];
cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"CellSelected_1x140.png"]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.titleLabel.text = venue.name;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (venueDetailView == nil) {
venueDetailView = [[VenueDetailViewController alloc] initWithNibName:@"VenueDetailViewController" bundle:[NSBundle mainBundle]];
FSVenue *venue = (FSVenue *)[venues objectAtIndex:indexPath.row];
venueDetailView.vid = venue.venueId;
[self.navigationController pushViewController:venueDetailView animated:YES];
}
venueDetailView = nil;
[venueDetailView release];
}
- (NSIndexPath *)tableView :(UITableView *)theTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (letUserSelectRow)
return indexPath;
else
return nil;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row % 2) {
[cell setBackgroundColor:[UIColor colorWithRed:((float)173 / 255.0f) green:((float)173 / 255.0f) blue:((float)176 / 255.0f) alpha:.60]];
} else {
[cell setBackgroundColor:[UIColor colorWithRed:((float)152 / 255.0f) green:((float)152 / 255.0f) blue:((float)156 / 255.0f) alpha:.60]];
}
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *titleHeader;
if ([venues count] == 0) {
titleHeader = @"No venues were found.";
} else {
titleHeader = @"";
}
return titleHeader;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 55;
}
#pragma mark -
#pragma mark Search Bar
- (void)searchBarTextDidBeginEditing:(UISearchBar *)theSearchbar {
//Add the overlay view.
if (overlayView == nil)
overlayView = [[OverlayViewController alloc] initWithNibName:@"OverlayViewController" bundle:[NSBundle mainBundle]];
CGFloat yaxis = self.navigationController.navigationBar.frame.size.height;
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;
//Parameters x = origin on x-axis, y = origin on y-axis.
CGRect frame = CGRectMake(0, yaxis, width, height);
overlayView.view.frame = frame;
overlayView.view.backgroundColor = [UIColor grayColor];
overlayView.view.alpha = 0.5;
overlayView.searchView = self;
[tv insertSubview:overlayView.view aboveSubview:self.parentViewController.view];
letUserSelectRow = NO;
tv.scrollEnabled = NO;
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)theSearchBar {
searchBar.showsScopeBar = YES;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:YES animated:YES];
return YES;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)theSearchBar {
searchBar.showsScopeBar = NO;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:NO animated:YES];
[self doneSearching_Clicked:nil];
return YES;
}
- (void) doneSearching_Clicked:(id)sender {
[searchBar resignFirstResponder];
letUserSelectRow = YES;
tv.scrollEnabled = YES;
[overlayView.view removeFromSuperview];
[overlayView release];
overlayView = nil;
//Reverse geocode postcode entered.
if (![searchBar.text isEqualToString:@""]) {
[self findPostcode:searchBar.text];
searchBar.text = @"";
[tv reloadData];
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)theSearchBar {
[self doneSearching_Clicked:nil];
}
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar {
[searchBar resignFirstResponder];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[tv reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[navBarTitle release];
[venueDetailView release];
[CLController release];
[tv release];
[venues release];
[primaryCategories release];
[categoryId release];
[responseData release];
[super dealloc];
}
@end