- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我希望有人可以帮助我解决这段代码,并尝试找出优化它的最佳方法,这样我就不会遇到这么多的竞争条件。
我知道正在发生的一些事情:
我只是认为总的来说这段代码可以变得更有效率。如果有人有任何建议,我将不胜感激。
我将在这里发布大部分代码,我已经删除了很多处理来保存行,因此阅读起来并不困难,但我认为我留下了足够的内容,以便您可以看到 GCD 的使用情况如果我做错了。如果您想查看整个内容,我还将在要点中链接完整的代码。
#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
文档中非常清楚地规定了此方法运行并在某个任意队列上调用回调,
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_enter 和 dispatch_group_leave 来管理并发任务是否更有意义?我没有看到您正在主线程中重新加载 collectionview。这些是我从上面的代码中看到的主要问题。如果您选择一些不同对象的服务代码,您将在以后重构和找出错误时节省大量时间。
关于ios - iOS 中的竞争条件使用 GCD 用于 UICollectionView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30536913/
假设我正在使用 APC,其中过程和调用代码都使用 SetLastError 和 GetLastError。这会导致 GetLastError 产生不可预测的值。有什么办法可以解决这个问题吗? VOID
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 7年前关闭。 Improve t
任何人都可以,请告诉我,如何在不进行JavaScript轮询/ setInterval的情况下,在完整日历上填充/显示在服务器端动态更新的数据。 grails中提供了Atmosphere插件,但是文档
我正在尝试调整我的代码,从仅在前台使用 WCSessionDelegate 回调到在后台通过 handleBackgroundTasks: 接受 WKWatchConnectivityRefreshB
我正在构建批处理系统。 单位 的批处理数量从 20 到 1000 不等。每个 Unit 本质上都是模型的层次结构(一个主模型和许多子模型)。我的任务涉及将每个模型层次结构作为单个事务保存到数据库中(每
我拍了一张图片并将其切成三 block ,然后将它们向右浮动,让文字围绕它们流动。 HTML 看起来像这样: 在我添加侧边栏并将其 float 到图像的右上方之前,它工作正常,就像这样... T
我正在考虑嵌入式 Linux 项目(还没有硬件)中即将出现的情况,其中两个外部芯片需要共享一条物理 IRQ 线。这条线在硬件中能够实现边沿触发,但不能实现电平触发中断。 查看 Linux 中的共享 i
我观察到,当 linux futexes 发生争用时,系统会在自旋锁上花费大量时间。我注意到即使不直接使用 futex 也是一个问题,但在调用 malloc/free、rand、glib 互斥调用和其
我终于能够获得一些工具提示,最终可以使用以下代码: Hover over me 然后 $('[rel=tooltip]').tooltip(); 我遇到的问题是它使用 jQueryUI 工
我是一名优秀的程序员,十分优秀!