Я пытаюсь загрузить некоторые данные из файла plist. Он содержит NSArray NSDictionaries с очень небольшим количеством данных (очень короткая строка и число). Проблема в том, что в нем около 8000 записей. Размер самого файла plist составляет около 900 кБ при хранении в формате XML и около 350 кБ при хранении в виде двоичного файла, но, очевидно, когда он загружается в память, он увеличивается до 510 МБ, что, по-видимому, и происходит при использовании анализатора распределения. Это в 50-60 раз больше размера диска.
Сначала я подумал, что, должно быть, произошла какая-то ошибка, но потом я понял, что очень мало знаю о накладных расходах памяти в Какао. Тем не мение. Я загружаю список следующим образом:
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
Теперь: есть какая-нибудь подсказка о том, почему при загрузке этого списка мне выделяется 510 МБ памяти? И, очевидно, он не освобождается, когда я отменяю поиск и восстанавливаю исходные данные в searchBarCancelButtonClicked
…