带有字典数组的plist文件的内存开销是多少?

时间:2012-03-12 10:26:30

标签: ios xcode nsarray plist nsdictionary

我正在尝试从plist文件加载一些数据。它包含一个NSArray的NSDuraries,每个都有很少的数据(一个非常短的字符串和一个数字)。问题是它有大约8000个条目。当作为XML存储时,plist文件本身大约为900 kB,当存储为二进制时,plist文件大约为350 kB,但显然当它被加载到内存中时,它扩展到大约510 MB,这就是使用分配分析器的情况。这就像磁盘大小的50-60k倍。

起初我认为肯定会出现某种错误,但后来我意识到我对Cocoa中的东西的内存开销很少。无论如何。我像这样加载了plist:

NSMutableArray *data = [[NSMutableArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"localita" ofType:@"plist"]];

然后我将它分配给我有这个自定义视图控制器的属性(非原子,强)

[cbVC setData:data];
[cbVC setFilteredData:data];

之前我覆盖了setData,但我改变了这种方式,看看这是不是问题 - 事实并非如此。所以,这是界面:

@protocol CityBrowserDelegate <NSObject>

- (void)cityPicked:(NSString *)cityName;

@end

@interface CityBrowserViewController : UIViewController <UITableViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate>

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope;
- (IBAction)selectionFinished:(id)sender;

@property (nonatomic, strong) NSMutableArray *data;
@property (nonatomic, strong) NSMutableArray *filteredData;

@property (nonatomic, strong) IBOutlet UITableView *tableView;

@property (nonatomic, strong) IBOutlet id<MyPopoverControllerDelegate, CityBrowserDelegate> delegate;

@end

这是实施(我剥离了不相关的部分)

@implementation CityBrowserViewController

@synthesize data = _data;
@synthesize filteredData = _filteredData;
@synthesize tableView = _tableView;
@synthesize delegate = _delegate;

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [self.filteredData count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.filteredData count] == 0 ? 1 : [self.filteredData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellID = @"BasicCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if(!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    if([self.filteredData count] == 0) {
        [cell.textLabel setText:@"Nessun risultato"];
    } else {
        [cell.textLabel setText:[[self.filteredData objectAtIndex:indexPath.row] valueForKey:@"Name"]];
    }
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *name = [[self.filteredData objectAtIndex:indexPath.row] valueForKey:@"Name"];
    [self.delegate cityPicked:name];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    [self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    _filteredData = _data;
}

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
    [_filteredData removeAllObjects]; // First clear the filtered array.

    // YES, I KNOW, but it seems to be quite fast nonetheless...
    NSDictionary *city;
    for (city in _data) {
        NSString *cityName = [city valueForKey:@"Name"];
        NSComparisonResult result = [cityName compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
        if (result == NSOrderedSame) {
            [_filteredData addObject:city];
        }
    }
}

- (void)selectionFinished:(id)sender {
    [self.delegate dismissPopover];
}

@end

现在:关于为什么在加载该plist时分配510 MB内存的任何线索?显然,当我取消搜索并恢复searchBarCancelButtonClicked中的原始数据时,它不会被取消分配...

1 个答案:

答案 0 :(得分:0)

问题是我给N个部分返回了N个部分,给定N是数据集的大小。显然不是最好的主意。数据集只有大约8000个条目,并且它不会很快改变,所以现在我将保留代码(明显更正)。在一个单独的分支中,我正在尝试核心数据。