for 循环中的内存泄漏 (Objective-C iPhone)

发布于 2024-10-06 01:19:37 字数 15765 浏览 1 评论 0原文

我的 - (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

I'm getting quite a few memory leaks with the loop in my - (void)connectionDidFinishLoading:(NSURLConnection *)connection method. Just wondering whether anyone can lead me in the right direction as to how to decrease the amount of memory leaks occurring? Perhaps it isn't the best code... any help with other areas would be greatly appreciated.

//  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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

还在原地等你 2024-10-13 01:19:37

如果 self.categoryId != nil![self.categoryId isEqualToString:primaryCategory.primaryCategoryId],则 primaryCategoryvenue代码> 被泄露。我只需将 [primaryCategory release] (对于 venue 也是如此)从分支中分解出来,并将其放在循环的末尾。

为了获得未来的帮助,您可能会喜欢 XCode 的“构建和分析”模式,该模式应该静态检测这种代码流泄漏,并准确地告诉您哪些分配在哪里泄漏。

If self.categoryId != nil and ![self.categoryId isEqualToString:primaryCategory.primaryCategoryId], then primaryCategory and venue are leaked. I'd just factor [primaryCategory release] (and the same for venue) out of the branches, and put it at the end of the loop.

For future help, you might like XCode's "Build and Analyse" mode, which should statically detect this kind of code flow leak and tell you exactly what allocation is leaked where.

荆棘i 2024-10-13 01:19:37

每当设置了 self.categoryId 但与 primaryCategory.primaryCategoryId 不匹配时,您就会泄漏 venueprimaryCategory

您的代码当然可以清理:

  • 添加一个 -[FSVenue initWithResult:] 方法。
  • 添加 -[FSPrimaryCategory initWithDictionary:] 方法。
  • 根据设备决定是否使用高分辨率图标。
  • 循环末尾的 if 语句包含重复的代码。考虑这样做:
for (...) {
    ...

    //Check if categories match the category selected from the FSCategory controllers.
    if (self.categoryId
        && ![self.categoryId isEqualToString:primaryCategory.primaryCategoryId]) {
        [venue release];
        [primaryCategory release];
        continue;
    }

    [venues addObject:venue];
    [venue release];

    [primaryCategories addObject:primaryCategory];
    [primaryCategory release];
}
  • 每当创建对象时,请考虑使用 autorelease。那么你一开始就不会泄露任何东西!

You are leaking the venue and primaryCategory whenever self.categoryId is set but does not match primaryCategory.primaryCategoryId.

Your code could certainly be cleaned up:

  • Add an -[FSVenue initWithResult:] method.
  • Add an -[FSPrimaryCategory initWithDictionary:] method.
  • Decide whether to use a high-resolution icon based on the device.
  • The if statements at the end of the loop contain duplicated code. Consider doing this instead:
for (...) {
    ...

    //Check if categories match the category selected from the FSCategory controllers.
    if (self.categoryId
        && ![self.categoryId isEqualToString:primaryCategory.primaryCategoryId]) {
        [venue release];
        [primaryCategory release];
        continue;
    }

    [venues addObject:venue];
    [venue release];

    [primaryCategories addObject:primaryCategory];
    [primaryCategory release];
}
  • Consider using autorelease whenever you create an object. Then you would not have leaked anything in the first place!
溺孤伤于心 2024-10-13 01:19:37

讨论结束后,我们添加了 Jeremy 的答案,这是代码建议。

在对象的 .h 文件中

@interface MyObject : UIViewController <UITableViewDelegate,UITableViewDataSource> {
    NSMutableArray *venues;
    NSMutableArray *primaryCategories;
}

@property (nonatomic,retain) NSMutableArray *venues;
@property (nonatomic,retain) NSMutableArray *primaryCategories;

在对象的 .m 文件中

@implementation MyObject

@synthesize venues;
@synthesize primaryCategories;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.venues = [[NSMutableArray alloc] init];
    self.primaryCategories = [[NSMutableArray alloc] init];
}

- (void)whatEverMethodYouLike {
    // The for loop here (with proper deallocs)
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    FSPrimaryCategory *primaryCategory = (FSPrimaryCategory *)[primaryCategories objectAtIndex:indexPath.row];
    // Et caetera
}

- (void)dealloc {
    [self.venues release];
    [self.primaryCategories release];
    [super dealloc];
}

After the discussion we add in Jeremy's answer, here's a suggestion of code.

In your object's .h file

@interface MyObject : UIViewController <UITableViewDelegate,UITableViewDataSource> {
    NSMutableArray *venues;
    NSMutableArray *primaryCategories;
}

@property (nonatomic,retain) NSMutableArray *venues;
@property (nonatomic,retain) NSMutableArray *primaryCategories;

In your object's .m file

@implementation MyObject

@synthesize venues;
@synthesize primaryCategories;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.venues = [[NSMutableArray alloc] init];
    self.primaryCategories = [[NSMutableArray alloc] init];
}

- (void)whatEverMethodYouLike {
    // The for loop here (with proper deallocs)
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    FSPrimaryCategory *primaryCategory = (FSPrimaryCategory *)[primaryCategories objectAtIndex:indexPath.row];
    // Et caetera
}

- (void)dealloc {
    [self.venues release];
    [self.primaryCategories release];
    [super dealloc];
}
窗影残 2024-10-13 01:19:37
venues = [[NSMutableArray alloc] init];
primaryCategories = [[NSMutableArray alloc] init];

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];

            [primaryCategories addObject:primaryCategory];
        }
    } else {
        [venues addObject:venue];

        [primaryCategories addObject:primaryCategory];
    }
    [primaryCategory release];
    [venue release];
}

除非它们满足插入数组的条件,否则您会泄漏场地和主要类别。该循环的正确结构如上。
我认为数组“venues”和“primaryCategories”是ivars,您可以在类的dealloc方法中释放它们。 (否则你也会泄漏这些数组。)

venues = [[NSMutableArray alloc] init];
primaryCategories = [[NSMutableArray alloc] init];

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];

            [primaryCategories addObject:primaryCategory];
        }
    } else {
        [venues addObject:venue];

        [primaryCategories addObject:primaryCategory];
    }
    [primaryCategory release];
    [venue release];
}

You're leaking venue and primaryCategory unless they meet the conditions to be inserted in the arrays. The correct structure of this loop is above.
I take it that the arrays 'venues' and 'primaryCategories' are ivars and you release them in the dealloc method of your class. (or else you're leaking those arrays too.)

洛阳烟雨空心柳 2024-10-13 01:19:37

你有一个泄漏primaryCategory,因为在if语句中你有另一个if语句..所以可能有内存泄漏的可能性

you have one leak primaryCategory , because inside the if statement u have another if statement .. so there might have possibilities of memory leak

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文