gpt4 book ai didi

ios - iOS 中的竞争条件使用 GCD 用于 UICollectionView

转载 作者:行者123 更新时间:2023-11-29 01:59:16 26 4
gpt4 key购买 nike

我希望有人可以帮助我解决这段代码,并尝试找出优化它的最佳方法,这样我就不会遇到这么多的竞争条件。

我知道正在发生的一些事情:

  • 有时甚至不显示 Collection View
  • 只有部分项目显示在 Collection View 中,即 8 项中的 3 项
  • 刷新图函数在任何地方随机调用 1-3 次

我只是认为总的来说这段代码可以变得更有效率。如果有人有任何建议,我将不胜感激。

我将在这里发布大部分代码,我已经删除了很多处理来保存行,因此阅读起来并不困难,但我认为我留下了足够的内容,以便您可以看到 GCD 的使用情况如果我做错了。如果您想查看整个内容,我还将在要点中链接完整的代码。

Gist

#import "DashboardCollectionViewController.h"
#import "DashboardLayout.h"
#import "HeaderViewCell.h"
#import "DashboardCell.h"
#import "DashboardDetailViewController.h"
#import "PreferencesManager.h"
#import "UIColor+HexColors.h"
#import "PNChart.h"

@interface DashboardCollectionViewController () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate>

@property (nonatomic, strong) DashboardLayout *listLayout;
@property (nonatomic, strong) DashboardLayout *gridLayout;
@property (strong, nonatomic) HKHealthStore *healthStore;
@property (strong, nonatomic) NSDictionary *dataTypes;
@property (strong, nonatomic) HeaderViewCell *headerCell;

@end

@implementation DashboardCollectionViewController
{

NSString *layoutType;
NSString *unitPreference;
NSMutableDictionary *itemData;
UIRefreshControl *refreshControl;
NSArray *sortedDashboardItems;
__block NSMutableArray *graphData;

}

@synthesize dashboardItems, allDashboardItems, myCollectionView, dataTypes, headerCell;

- (void)viewDidLoad {

[super viewDidLoad];
// Do any additional setup after loading the view.

[self setupFlowLayoutA];
[self setupFlowLayoutB];

layoutType = @"listView";
dataTypes = [NSDictionary dictionaryWithObjectsAndKeys:
@1, HKQuantityTypeIdentifierStepCount,
@2, HKQuantityTypeIdentifierFlightsClimbed,
@3, HKQuantityTypeIdentifierDistanceWalkingRunning,
@4, HKQuantityTypeIdentifierActiveEnergyBurned,
@5, HKQuantityTypeIdentifierBodyMass,
@6, HKQuantityTypeIdentifierDistanceCycling,
@7, HKQuantityTypeIdentifierHeartRate,
@8, HKQuantityTypeIdentifierBodyMassIndex, nil];

UINib *headerNib = [UINib nibWithNibName:@"HeaderView" bundle:nil];
UINib *cellNib = [UINib nibWithNibName:@"DashboardCell" bundle:nil];
DashboardLayout *dashboardLayout = [self listLayout];

[myCollectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderCell"];
[myCollectionView registerNib:cellNib forCellWithReuseIdentifier:@"Cell"];
[myCollectionView setCollectionViewLayout:dashboardLayout animated:YES];

//check if health kit is available on this device
if ([HKHealthStore isHealthDataAvailable]) {

if (!self.healthStore) {
self.healthStore = [HKHealthStore new];
}
}

refreshControl = [UIRefreshControl new];
[refreshControl addTarget:self action:@selector(refreshAllData) forControlEvents:UIControlEventValueChanged];
[myCollectionView addSubview:refreshControl];

}

- (void)viewWillAppear:(BOOL)animated {

[super viewWillAppear:animated];

//set data types we want to read and write
NSSet *dataTypesToWrite = [self dataTypesToWrite];
NSSet *datatTypesToRead = [self dataTypesToRead];

allDashboardItems = [self loadDashboardItems];
unitPreference = [self loadUnitPreferences];
dashboardItems = [NSMutableArray new];
itemData = [NSMutableDictionary new];

for (NSDictionary *item in allDashboardItems) {

NSString *enabled = item[@"enabled"];

if ([enabled isEqualToString:@"1"]) {
[dashboardItems addObject:item];
}

}

NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"order" ascending:YES];
sortedDashboardItems = [dashboardItems sortedArrayUsingDescriptors:@[descriptor]];

graphData = [[NSMutableArray alloc] initWithCapacity:[sortedDashboardItems count]];

for (int i=0; i < [sortedDashboardItems count]; i++) {

[graphData addObject:[NSNull null]];

}

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
#if DEBUG
NSLog(@"%@", [defaults objectForKey:@"unitPreference"]);
#endif

//request authorization
[self.healthStore requestAuthorizationToShareTypes:dataTypesToWrite readTypes:datatTypesToRead completion:^(BOOL success, NSError *error) {
if (!success) {
//user did not authorize healthkit
NSLog(@"Health Kit was not given the correct permissions");
return;
} else {

[self refreshData];
[self refreshGraphs];
// [myCollectionView reloadData];

}
}];

[self refreshData];
[self refreshGraphs];
// [myCollectionView reloadData];

}

- (void)refreshAllData {

[self refreshData];
[self refreshGraphs];

}

- (void)refreshData {

__block NSString *labelString = @"";
__block NSString *unitString = @"";

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *startDate = [calendar startOfDayForDate:[NSDate date]];
NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0];
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];

for (NSDictionary *item in sortedDashboardItems) {

NSString *type = item[@"type"];

HKSampleType *sampleType = [HKSampleType quantityTypeForIdentifier:type];

HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {

if (!results) {

NSLog(@"No results were returned form query");

} else if (error) {

NSLog(@"Error: %@ %@", error, [error userInfo]);

} else {

dispatch_async(dispatch_get_main_queue(), ^{

//processing

int order = [item[@"order"] intValue];
NSNumber *orderNumber = [NSNumber numberWithInt:order];

UIFont *arialLarge = [UIFont fontWithName:@"AvenirNext-Bold" size:15.0];
UIFont *arialSmall = [UIFont fontWithName:@"AvenirNext-Bold" size:8.0];
NSDictionary *arialLargeDict = @{NSFontAttributeName : arialLarge};
NSDictionary *arialSmallDict = @{NSFontAttributeName : arialSmall};

NSMutableAttributedString *largeString = [[NSMutableAttributedString alloc] initWithString:labelString attributes:arialLargeDict];
NSMutableAttributedString *smallString = [[NSMutableAttributedString alloc] initWithString:unitString attributes:arialSmallDict];

[largeString appendAttributedString:smallString];

[itemData setObject:largeString forKey:orderNumber];

[myCollectionView reloadData];
[refreshControl endRefreshing];

});

}

}];

[self.healthStore executeQuery:query];

}

}

- (void)refreshGraphs {

#if DEBUG
NSLog(@"graphs");
#endif
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *interval = [NSDateComponents new];
interval.day = 1;

NSDate *anchorDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:-6 toDate:[calendar startOfDayForDate:[NSDate date]] options:0];

dispatch_queue_t queue = dispatch_queue_create([@"graph.queue" UTF8String], DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();

for (NSDictionary *item in sortedDashboardItems) {

NSMutableArray *arrayOfValues = [NSMutableArray new];

NSString *type = item[@"type"];

NSUInteger index = [sortedDashboardItems indexOfObject:item];

HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:type];

NSDate *endDate = [NSDate date];

NSDate *startDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:-6 toDate:[calendar startOfDayForDate:endDate] options:0];

dispatch_block_t block = ^{

dispatch_semaphore_t lock = dispatch_semaphore_create(0);

if ([type isEqualToString:HKQuantityTypeIdentifierBodyMass]) {

HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options:HKStatisticsOptionDiscreteAverage anchorDate:anchorDate intervalComponents:interval];

query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {

//processing

};

[self.healthStore executeQuery:query];

dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);

} else if ([type isEqualToString:HKQuantityTypeIdentifierBodyMassIndex]) {

HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options:HKStatisticsOptionDiscreteAverage anchorDate:anchorDate intervalComponents:interval];

query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {

//processing

};

[self.healthStore executeQuery:query];

dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);

} else if ([type isEqualToString:HKQuantityTypeIdentifierHeartRate]) {

HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options:HKStatisticsOptionDiscreteAverage anchorDate:anchorDate intervalComponents:interval];

query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {

//processing

};

[self.healthStore executeQuery:query];

dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);

} else {

HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options:HKStatisticsOptionCumulativeSum anchorDate:anchorDate intervalComponents:interval];

query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {

if (error) {

NSLog(@"Error: %@ %@", error, [error userInfo]);

} else {

[results enumerateStatisticsFromDate:startDate toDate:endDate withBlock:^(HKStatistics *result, BOOL *stop) {

HKQuantity *quantity = result.sumQuantity;

if (quantity != nil) {

//do some processing

} else {

[arrayOfValues addObject:@0];

}

}];

[self addArrayToGraphData:arrayOfValues atIndex:index];

dispatch_semaphore_signal(lock);

}

};

[self.healthStore executeQuery:query];

dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);

};

};

dispatch_group_async(group, queue, block);

}

dispatch_group_notify(group, queue, ^{

[myCollectionView reloadData];

});

}

- (void)addArrayToGraphData:(NSArray *)array atIndex:(NSUInteger)index {

[graphData replaceObjectAtIndex:index withObject:array];

}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

DashboardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];

if (cell != nil) {

for (UIView *subview in cell.subviews) {

if ([subview isKindOfClass:[PNLineChart class]]) {

[subview removeFromSuperview];

}

}

NSNumber *indexNumber = [NSNumber numberWithInteger:indexPath.row];
NSDictionary *item = [sortedDashboardItems objectAtIndex:indexPath.row];
NSString *imageSafeString = [item[@"title"] stringByReplacingOccurrencesOfString:@" " withString:@""];
NSString *imageString = @"";

if ([layoutType isEqualToString:@"listView"]) {

imageString = [NSString stringWithFormat:@"%@-large.png", imageSafeString];
cell.layoutType = layoutType;
cell.titleLabel.text = item[@"title"];
cell.dataImage.image = [UIImage imageNamed:imageString];

} else if ([layoutType isEqualToString:@"gridView"]) {

imageString = [NSString stringWithFormat:@"%@-small.png", imageSafeString];
cell.layoutType = layoutType;
cell.titleLabel.text = @"";
cell.dataImage.image = [UIImage imageNamed:imageString];

}

PNLineChart *graph = nil;

if ([layoutType isEqualToString:@"listView"]) {

graph = [[PNLineChart alloc] initWithFrame:CGRectMake(80, 50, self.view.frame.size.width - 100, 90)];

} else {

graph = [[PNLineChart alloc] initWithFrame:CGRectMake(10, 0, (self.view.frame.size.width / 2) - 50, 110)];

}

graph.showLabel = NO;
graph.showGenYLabels = NO;
graph.backgroundColor = [UIColor clearColor];
graph.pointColor = [UIColor whiteColor];
graph.userInteractionEnabled = NO;

[cell addSubview:graph];

PNLineChartData *data = [PNLineChartData new];
data.color = [UIColor colorWithHexString:@"49b1d9"];
if (![graphData[indexPath.row] isEqual:[NSNull null]]) {
data.itemCount = [graphData[indexPath.row] count];
} else {
data.itemCount = 0;
}
data.inflexionPointStyle = PNLineChartPointStyleCircle;
data.getData = ^(NSUInteger index) {

CGFloat yValue = [graphData[indexPath.row][index] floatValue];
return [PNLineChartDataItem dataItemWithY:yValue];

};

graph.chartData = @[data];
[graph strokeChart];

NSAttributedString *dataString = [itemData objectForKey:indexNumber];

cell.dataLabel.attributedText = dataString;

}

return cell;

}

最佳答案

看起来代码太复杂了,任何人都无法查看它并猜测实际发生了什么。如果您将它分成一些适当的模型或服务层,这样会更好,这样进行展示的代码和从 healthkit 获取数据的代码将是分开的。

我清楚地看到这里的线程问题,首先是 HKHealthStore 方法的使用,

- (void)requestAuthorizationToShareTypes:(NSSet *)typesToShare
readTypes:(NSSet *)typesToRead
completion:(void (^)(BOOL success,
NSError *error))completion

文档中非常清楚地规定了此方法运行并在某个任意队列上调用回调,

https://developer.apple.com/library/prerelease/ios/documentation/HealthKit/Reference/HKHealthStore_Class/index.html#//apple_ref/occ/instm/HKHealthStore/requestAuthorizationToShareTypes:readTypes:completion :

HealthKit performs these requests asynchronously. If you call this method with a new data type (a type of data that the user has not previously granted or denied permission for in this app), the system automatically displays the permission form, listing all the requested permissions. After the user has finished responding, this method calls its completion block on a background queue. If the user has already chosen to grant or prohibit access to all of the types specified, the completion is called without prompting the user.

现在,您真的确定所有的 UI 调用都是在主线程中进行的吗?我认为您正在执行多个异步查询。所以,在这种情况下,dispatch_semaphore 看起来并不复杂。使用 dispatch_group_enterdispatch_group_leave 来管理并发任务是否更有意义?我没有看到您正在主线程中重新加载 collectionview。这些是我从上面的代码中看到的主要问题。如果您选择一些不同对象的服务代码,您将在以后重构和找出错误时节省大量时间。

关于ios - iOS 中的竞争条件使用 GCD 用于 UICollectionView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30536913/

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