0

我有一些方法需要一些时间来处理获取数据、执行计算然后返回结果,例如这个实例方法返回一个基于三个参数的数组:

-(NSArray*)periodsForCompanies:(NSArray*)companies figureType:(NSString*)figureType
actualValuesOnly:(BOOL)actualValuesOnly
    {.. };

由于此方法可以使用同一类的相同参数多次调用并且需要一些时间才能完成,因此我想优化我的代码以避免每次都完全执行此方法的代码。

我如何将先前的参数(和/或结果)存储在方法中,以便能够将当前参数与先前的参数进行比较并决定是否需要再次执行代码?在这种情况下,什么是“最佳实践”?

我的理解是,当调用该方法时,通常他方法中的所有变量都会重置为零和零。

编辑

根据要求,我添加了一个代码示例:

- (NSArray*)periodsForCompanies:(NSArray*)companies figureType:(NSString*)figureType actualValuesOnly:(BOOL)actualValuesOnly
{
    // fetch all periods
    
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"IBEstPeriod"];
    NSPredicate *predicate = [[NSPredicate alloc]init];
    
    if (actualValuesOnly == YES)
        predicate = [NSPredicate predicateWithFormat:@"(company IN %@) AND (ANY estType.actValue != nil) AND (ANY estType.type == %@)", self.companies, figureType];
    else
        predicate = [NSPredicate predicateWithFormat:@"(company IN %@) AND (ANY estType.type == %@)", self.companies, figureType];
    
    request.predicate = predicate;
    request.resultType = NSDictionaryResultType;
    request.returnsDistinctResults = YES;
    request.propertiesToFetch = @[@"endCalYear",@"endMonth",@"periodLength"];
    request.sortDescriptors =
        @[[NSSortDescriptor sortDescriptorWithKey:@"endCalYear"     ascending:NO],
        [NSSortDescriptor   sortDescriptorWithKey:@"endMonth"       ascending:NO],
        [NSSortDescriptor   sortDescriptorWithKey:@"periodLength"   ascending:NO]];
    
    NSError *fetchError = nil;
    NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&fetchError];
    
    NSMutableArray *distinctPeriods = results.mutableCopy;
    
    if (fetchError) {
        NSLog(@"Error during fetch request:%@", [fetchError localizedDescription]);
    } else {
        // NSLog(@"results: %@",results);
    }
    // remove periods for which not all companies have data for estimate type specified
    
    NSString const *endCalYearKey = @"endCalYear";
    NSString const *endMonthKey = @"endMonth";
    NSString const *periodLengthKey = @"periodLength";
    
    const NSIndexPath *yoyGrowthIndexPath =     [NSIndexPath indexPathForRow:0 inSection:0];
    const NSIndexPath *seqGrowthIndexPath =     [NSIndexPath indexPathForRow:1 inSection:0];
    const NSIndexPath *customGrowthIndexPath =  [NSIndexPath indexPathForRow:2 inSection:0];
    
    NSMutableIndexSet *indexesForPeriodsToRemove = [NSMutableIndexSet indexSet];
    
    [distinctPeriods enumerateObjectsUsingBlock:^(NSDictionary *estPeriodDict, NSUInteger idx, BOOL *stop) {
        
        NSNumber *endCalYear = estPeriodDict[endCalYearKey];
        NSNumber *endMonth = estPeriodDict[endMonthKey];
        NSNumber *periodLength = estPeriodDict[periodLengthKey];
        
        NSPredicate *predicate = [[NSPredicate alloc]init];
        UITableView *tableView = [self tableView];
        
        if ( [[tableView indexPathForSelectedRow] isEqual:customGrowthIndexPath] ) {
            
            // company predicate:
            
            predicate = [NSPredicate predicateWithFormat: @"ANY estimateType.type == %@ "
                         "AND SUBQUERY(estimatePeriod, $x, $x.endCalYear == %@ AND $x.endMonth == %@ AND $x.periodLength == %@ AND ANY $x.estType.type == %@).@count > 0",
                         figureType,
                         endCalYear, endMonth, periodLength, figureType];
            
        } else if ( [[tableView indexPathForSelectedRow] isEqual:yoyGrowthIndexPath] ) {
            
            predicate = [NSPredicate predicateWithFormat: @"ANY estimateType.type == %@ "
                         "AND SUBQUERY(estimatePeriod, $x, $x.endCalYear == %@ AND $x.endMonth == %@ AND $x.periodLength == %@ AND ANY $x.estType.type == %@).@count > 0"
                         "AND SUBQUERY(estimatePeriod, $x, $x.endCalYear == %i AND $x.endMonth == %@ AND $x.periodLength == %@ AND ANY $x.estType.type == %@).@count > 0",
                         figureType,
                         endCalYear, endMonth, periodLength, figureType,
                         endCalYear.integerValue - 1, endMonth, periodLength, figureType];
            
        } else if  ( [[tableView indexPathForSelectedRow] isEqual:seqGrowthIndexPath] ) {
            
            // TODO: rewrite
            predicate = [NSPredicate predicateWithFormat: @"ANY estimateType.type == %@ "
                         "AND SUBQUERY(estimatePeriod, $x, $x.endCalYear == %@ AND $x.endMonth == %@ AND $x.periodLength == %@ AND ANY $x.estType.type == %@).@count > 0",
                         figureType,
                         endCalYear, endMonth, periodLength, figureType];
        } else {
            [NSException raise:NSInternalInconsistencyException format:@"TableView: Invalid selection state in section 0 (NSIndexPath: %@)",super.tableView.indexPathForSelectedRow];
        }
        
        NSArray *companiesWithDataForPeriod = [self.companies filteredArrayUsingPredicate:predicate];
        NSLog(@"type: %@, period: %@/%@(%@), companies: %@", figureType, endCalYear, endMonth, periodLength,[companiesWithDataForPeriod valueForKey:@"contrSymbol"]);
        
        // mark periods which are not defined for all companies for removal (from display):
        if ( companiesWithDataForPeriod.count < self.companies.count ) [indexesForPeriodsToRemove addIndex:idx];
        
    }]; // end block
    
    [distinctPeriods removeObjectsAtIndexes:indexesForPeriodsToRemove];
    return distinctPeriods;
}
4

2 回答 2

1

您需要进行某种缓存,实际上您的参数可能会有很大差异,因为您有公司数组作为参数。如果您使用大量组合调用此方法,这可能会导致使用大量内存。

我会将其更改为仅通过单个公司,因此缓存会更小,而不是在最坏的情况下保留所有公司组合。

要将数据保存在缓存中,您可以创建一些NSMutableDictionary属性或静态值(记得在某处释放/清空它),然后作为键,您可以将这些参数组合在某个对象中或作为一个简单的字符串。

因此,您的方法的内部实现如下所示:

simpleString = .. combined arguments ...
NSArray *result = [dictionary objectForKey:simpleString]
if (result == nil)
{
    .. do fetch and put result in result
    [dictionary setObject:result forKey:simpleString];
}
return result;
于 2012-10-25T14:31:45.207 回答
1

您想缓存获取的结果。

假设您只想在运行时缓存结果,并在重新启动应用程序时重新获取它们。在这种情况下,请使用内部类和NSMutableDictionary. 添加属性

@property (nonatomic, strong, readwrite) NSMutableDictionary *periodsForParameters;

将以下类添加到您的源 ( .m) 文件中:

@interface PeriodRequestParameters : NSObject <NSCopying>
+ (PeriodRequestParameters *)parametersWithCompanies:(NSArray *)companies figureType:(NSString *)figureType actualValuesOnly:(BOOL)actualValuesOnly;
@property (nonatomic, strong, readwrite) NSArray *companies;
@property (nonatomic, strong, readwrite) NSString *figureType;
@property (nonatomic, assign, readwrite) BOOL actualValuesOnly;
- (BOOL)isEqualToPeriodRequestParameters:(PeriodRequestParameters *)comparand;
@end

@implementation PeriodRequestParameters

@synthesize companies, figureType, actualValuesOnly;

+ (PeriodRequestParameters *)parametersWithCompanies:(NSArray *)companies figureType:(NSString *)figureType actualValuesOnly:(BOOL)actualValuesOnly
{
    PeriodRequestParameters *res = [[PeriodRequestParameters alloc] init];
    res.companies = companies;
    res.figureType = figureType;
    res.actualValuesOnly = actualValuesOnly;
    return res;
}

- (BOOL)isEqualToPeriodRequestParameters:(PeriodRequestParameters *)comparand
{
    return ([self.companies isEqual:comparand.companies] &&
            [self.figureType isEqual:comparand.figureType] &&
            self.actualValuesOnly == comparand.actualValuesOnly);
}


// These methods are used by NSDictionary, so they must be overridden.
- (BOOL)isEqual:(id)object
{
    BOOL res = NO;
    if ([object isMemberOfClass:[PeriodRequestParameters class]]) {
        res = [self isEqualToPeriodRequestParameters:object];
    }
    return res;
}

- (NSUInteger)hash
{
    //This method can be made better, but this will work.
    return self.companies.hash;
}

//NSCopying

- (id)copyWithZone:(NSZone *)zone
{
    PeriodRequestParameters *res = [[PeriodRequestParameters allocWithZone:zone] init];
    res.companies = self.companies.copy;
    res.figureType = self.figureType.copy;
    res.actualValuesOnly = self.actualValuesOnly;
    return res;
}

@end

此类为您提供了一种将传入的参数用作字典periodsForCompanies:figureType:actualValuesOnly:中的键的方法。periodsForParameters现在,在您获取结果后,您可以将获取的数组添加为键的对象,[PeriodRequestParameters parametersWithCompanies:companies figureType:figureType actualValuesOnly:actualValuesOnly]其中companies,figureTypeactualValuesOnly是传递给 的参数periodForCompanies:figureType:actualValuesOnly:

然后,每次调用时,首先检查缓存periodForCompanies:figureType:actualValuesOnly:中是否已经存在条目。periodsForParameters

您可以使用 anNSDictionary作为periodsForParameters字典中的键,但在我看来,使用自定义类的代码看起来更简洁:您不必处理多个字符串作为键或在检查是否有时手动构建字典缓存结果或将新获取的结果添加到缓存中时。

于 2012-10-25T14:33:51.327 回答