gpt4 book ai didi

ios - 核心数据的UISearchBar性能问题

转载 作者:行者123 更新时间:2023-12-01 17:19:17 25 4
gpt4 key购买 nike

当我使用UISearchBar并将某些内容写为搜索字符串时,整个搜索过程会变得有点落后。我的猜测是我在主线程中弄乱了UI内容和Core Data,但我可能错了。而且,我对所有这些东西使用一个实体,因此没有关系等。此表中有3321个对象,此应用程序大约消耗 12至14 MB RAM RAM,您可以在下面的屏幕截图中看到:

我认为这样会更有效,因为3321个对象不是很多。对于所有核心数据,我都使用MagicalReacord。我对NSFetchedResultController的一个实例进行操作,但是在主表 View 和搜索表 View 之间切换NSPredicate
,但是没有什么比源代码更有值(value)了,所以在这里:

#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分开...并不是太拖ggy,UI不得不等待一段时间才能重新加载表 View 。但这是正确的方法吗?我必须提高此 UISearchBar的性能,因为我不想有不满意的客户。
我希望您可以向我介绍一些想法,或者您对我的代码有任何改进

最佳答案

首先,CONTAINS很慢。尽管这些信息不能解决您的问题,但很高兴知道您正在奋力奋斗。

其次,您要在每个按字母的位置打磁盘。那是浪费,当然很慢。

您正在使用Magical Record,它似乎在每次按字母时都会构建一个新的NSFetchedResultsController。那是浪费,当然很慢。

你该怎么办?

在第一个字母上,按一个简单的NSFetchRequest并减小批处理大小,甚至减小取回限制。保留其中的NSArray并使用它显示结果。 是的,这会使您的UITableViewDataSource更复杂。

在第二个及后续字母上,按,将过滤为现有NSArray 。您不返回磁盘。

如果检测到删除,则删除阵列并从磁盘重建它。

这会将您的磁盘命中次数限制为仅第一个字母,并且在检测到删除时将大大增加您的搜索时间。

更新

关于魔术唱片。我对第三方框架有很灰白的见解。我总是建议避免使用它们。这种避免与代码质量无关,而与代码质量尽可能地接近金属无关。 MR是核心数据之上的一层,我看不到任何值。当然,我也不喜欢点语法,因此请多加注意:)

是的,您应该将第一个搜索结果存储在一个数组中,然后针对该数组进行显示。会更快。

至于CONTAINS;不知道是否可以避免。它的速度很慢,但是可以正常工作,并且您正在进行字符串比较,因此在这方面您无能为力。因此,请修复所有其他问题,以免您支付不必要的计算税。

关于ios - 核心数据的UISearchBar性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20999569/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com