【发布时间】:2014-01-08 15:18:29
【问题描述】:
当我使用UISearchBar 并写一些东西作为搜索字符串整个搜索变得有点滞后。我的猜测是我在主线程中弄乱了 UI 的东西和核心数据,但我可能错了。更重要的是,我对所有这些东西都使用一个实体,所以没有关系等。这个表中有 3321 个对象,这个应用程序消耗大约 12 到 14 MB 的 RAM 你可以看到在下面的屏幕截图中:
我认为它会更有效,因为 3321 个对象并不多。对于所有核心数据,我使用MagicalReacord。我对NSFetchedResultController 的一个实例进行操作,但在主表视图和搜索表视图之间切换NSPredicate。
但是没有什么比源代码更有价值的了,所以你去吧:
#import "GroupsViewController.h"
#import "CashURLs.h"
#import "Group.h"
#import <AFNetworking.h>
@interface GroupsViewController ()
{
NSPredicate *resultPredicate;
UIRefreshControl *refreshControl;
}
@property (strong, nonatomic) NSMutableArray *selectedGroups;
@property (strong, nonatomic) NSFetchedResultsController *groupsFRC;
@end
@implementation GroupsViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Getting array of selected groups
self.selectedGroups = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedGroups"]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
resultPredicate = nil;
// Initializing pull to refresh
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshData) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
// Check if there is at least one Group entity in persistat store
if (![Group MR_hasAtLeastOneEntity]) {
[self refreshData];
} else {
[self refreshFRC];
[self.tableView reloadData];
}
}
#pragma mark - Downloading
-(void)refreshData
{
// Show refresh control
[refreshControl beginRefreshing];
// On refresh delete all previous groups (To avoid duplicates and ghost-groups)
[Group MR_truncateAll];
[[AFHTTPRequestOperationManager manager] GET:ALL_GROUPS parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
// For each group from downloaded JSON...
for (id group in responseObject) {
// ... Create entity and filll it with data
Group *groupEntity = [Group MR_createEntity];
groupEntity.name = [group valueForKey:@"name"];
groupEntity.cashID = [group valueForKey:@"id"];
groupEntity.sectionLetter = [[[group valueForKey:@"name"] substringToIndex:1] uppercaseString];
groupEntity.caseInsensitiveName = [[group valueForKey:@"name"] lowercaseString];
}
// Save Groups to persistent store
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
[self refreshFRC];
[self.tableView reloadData];
[refreshControl endRefreshing];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Failed to load data: %@", [error localizedDescription]);
// End refreshing
[refreshControl endRefreshing];
// Show alert with info about internet connection
UIAlertView *internetAlert = [[UIAlertView alloc] initWithTitle:@"Ups!" message:@"Wygląda na to, że nie masz połączenia z internetem" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[internetAlert show];
}];
}
#pragma mark - Table View
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Count sections in FRC
return [[self.groupsFRC sections] count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Count groups in each section of FRC
return [[[self.groupsFRC sections] objectAtIndex:section] numberOfObjects];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get reusable cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GroupCell"];
// If there isn't any create new one
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"GroupCell"];
}
Group *group = [self.groupsFRC objectAtIndexPath:indexPath];
cell.textLabel.text = group.name;
// Checking if group has been selected earlier
if ([self.selectedGroups containsObject:@{@"name" : group.name, @"id" : group.cashID}]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}
// Adding checkmark to selected cell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
Group *group = [self.groupsFRC objectAtIndexPath:indexPath];
// Checking if selected cell has accessory view set to checkmark and add group to selected groups array
if (selectedCell.accessoryType == UITableViewCellAccessoryNone)
{
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedGroups addObject:@{@"name" : group.name, @"id" : group.cashID}];
NSLog(@"%@", self.selectedGroups);
}
else if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
selectedCell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedGroups removeObject:@{@"name" : group.name, @"id" : group.cashID}];
NSLog(@"%@", self.selectedGroups);
}
// Hiding selection with animation for nice and clean effect
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - Filtering/Searching
// Seting searching predicate if there are any characters in search bar
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length > 0) {
resultPredicate = [NSPredicate predicateWithFormat:@"SELF.caseInsensitiveName CONTAINS[c] %@", searchText];
} else {
resultPredicate = nil;
}
[self refreshFRC];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
// If user cancels searching we set predicate to nil
resultPredicate = nil;
[self refreshFRC];
}
// Refreshing NSFetchedResultController
- (void)refreshFRC
{
self.groupsFRC = [Group MR_fetchAllSortedBy:@"caseInsensitiveName"
ascending:YES
withPredicate:resultPredicate
groupBy:@"sectionLetter"
delegate:self];
}
我在一个thread 中读到CONTAINS 可能会消耗资源,但我真的不知道如何以其他方式实现它。 我的另一个猜测是将此搜索放在另一个 queue 中并异步执行,将其与 UI 分开... UI 将不得不等待很长时间才能重新加载表并不那么滞后看法。但这是正确的方法吗?我必须提高这个UISearchBar 的性能,因为我不想让客户不满意。
我希望你能给我一些想法,或者你对我的代码有任何改进
【问题讨论】:
-
fetchBatchSize是否设置在任何地方(因此 fetch 不会尝试返回比您需要的更多的数据)? -
不...会检查的!但我真的不认为
MagicalRecords确实需要这批...
标签: ios multithreading uitableview core-data nspredicate