【问题标题】:Optimise slow code - enumeration of dictionary优化慢代码——字典的枚举
【发布时间】:2011-04-26 12:12:25
【问题描述】:

我有以下代码将 JSON 字符串解码为对象数组,然后我可以在 UITableView 中使用这些对象。

起初我认为 JSON 解码是缓慢的部分,但它似乎不是因为“字典完成”几乎立即出现。

关于如何让代码更快一点的任何想法?

-(void)parseJSON:(NSString *)jsonData{

    NSLog(@"Start parsing");
    NSDictionary *deserializedData = [jsonData objectFromJSONString];
    NSLog(@"Dictionary Done");

    NSArray *flights = [deserializedData valueForKeyPath:@"flights.flight"];
    NSMutableArray *localArray = [[NSMutableArray alloc] init ];
    NSString *lastFlightno =@"";

    for (NSDictionary *flight in flights){

        ArchiveFlight *aFlight = [[ArchiveFlight alloc] initWithFlightno:[flight objectForKey:@"flightno"] route:[flight objectForKey:@"route"]];
        aFlight.flightID = [flight objectForKey:@"primary_key"];
        aFlight.timeStamp = [aFlight niceDate:[flight objectForKey:@"timestamp"]];

        if (![lastFlightno isEqualToString:aFlight.flightno]) {
            [localArray addObject:aFlight];
        }

        lastFlightno =aFlight.flightno;
        [aFlight release];
    }
    NSLog(@"End Parsing");
    [self loadupTable:localArray];
    self.flightArray = localArray;
    [localArray release];

}

编辑:添加时间戳

NSLogs 的时间戳如下...

2011-04-26 13:22:36.104 App[1778:707] Finished request
2011-04-26 13:22:36.109 App[1778:707] Start parsing
2011-04-26 13:22:36.128 App[1778:707] Dictionary Done
2011-04-26 13:22:37.713 App[1778:707] End Parsing

JSON 示例...

{"flights":[{"flight":{"flightno":"RYR54WP","timestamp":"2011-04-26 12:13:04","route":"EGNX-LEAL","primary_key":"836453"}},{"flight":{"flightno":"RYR24LU","timestamp":"2011-04-26 09:14:03","route":"EVRA-EGNX","primary_key":"831318"}},{"flight":{"flightno":"RYR39WH","timestamp":"2011-04-26 05:33:03","route":"EGNX-EVRA","primary_key":"825492"}},{"flight":{"flightno":"RYR7PX","timestamp":"2011-04-25 20:07:03","route":"LELC-EGNX","primary_key":"816703"}},{"flight":{"flightno":"RYR2VB","timestamp":"2011-04-25 16:57:06","route":"EGNX-LELC","primary_key":"810900"}},{"flight":{"flightno":"RYR3JN","timestamp":"2011-04-25 12:36:04","route":"GCTS-EGNX","primary_key":"802631"}},{"flight":{"flightno":"RYR8GV","timestamp":"2011-04-25 06:07:03","route":"EGNX-GCTS","primary_key":"792945"}},{"flight":{"flightno":"RYR82QR","timestamp":"2011-04-24 19:42:04","route":"EPKK-EGNX","primary_key":"783306"}},{"flight":{"flightno":"RYR51PV","timestamp":"2011-04-24 16:31:05","route":"EGNX-EPKK","primary_key":"777835"}},{"flight":{"flightno":"RYR53AQ","timestamp":"2011-04-24 14:09:05","route":"LIME-EGNX","primary_key":"773572"}},{"flight":{"flightno":"RYR1CX","timestamp":"2011-04-24 11:02:05","route":"EGNX-LIME","primary_key":"768285"}},{"flight":{"flightno":"RYR9ZW","timestamp":"2011-04-24 08:21:04","route":"LEGE-EGNX","primary_key":"764624"}},{"flight":{"flightno":"RYR63BC","timestamp":"2011-04-24 05:48:02","route":"EGNX-LEGE","primary_key":"761726"}},{"flight":{"flightno":"RYR7PX","timestamp":"2011-04-23 19:39:03"

格式化样本:

{
   "flights":[
      {
         "flight":{
            "flightno":"RYR54WP",
            "timestamp":"2011-04-26 12:13:04",
            "route":"EGNX-LEAL",
            "primary_key":"836453"
         }
      },
      {
         "flight":{
            "flightno":"RYR24LU",
            "timestamp":"2011-04-26 09:14:03",
            "route":"EVRA-EGNX",
            "primary_key":"831318"
         }
      }
   ]
}

编辑 2:

所以这是导致减速的“niceDate”!

-(NSString *)niceDate:(NSString *)oldDate{
    NSDateFormatter *formatter = [[[NSDateFormatter alloc] init]autorelease];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *sourceDate = [formatter dateFromString:oldDate];
    NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
    [dateFormatter setDateStyle:NSDateFormatterFullStyle];
    [dateFormatter setTimeStyle:NSDateFormatterLongStyle];
    NSString *timeString = [dateFormatter stringFromDate:sourceDate];
    return [NSString stringWithFormat:@"%@",timeString];
}

【问题讨论】:

  • 您是否输入了一些分析时间戳以查看哪个部分占用的时间最多?
  • 添加了一些时间戳,但不能真正在循环中插入一些时间戳,否则速度会变慢!
  • 我们说的是多少次迭代?您可以输入一些日志记录代码,然后查看您的循环在前 10/50/100 次迭代中的表现。也许是因为某些原因导致性能下降?
  • 哦,当然,有 1000 行,唯一随时间增加的位是快速枚举中的位
  • @Lee 下一步是展示您的-niceDate: 方法。

标签: iphone objective-c json ios


【解决方案1】:

想到的一些事情:

NSArray *flights = [deserializedData valueForKeyPath:@"flights.flight"];

你需要使用KVC吗?您的 JSON 数据的结构是什么?

ArchiveFlight *aFlight = [[ArchiveFlight alloc] initWithFlightno:[flight objectForKey:@"flightno"] route:[flight objectForKey:@"route"]];
aFlight.flightID = [flight objectForKey:@"primary_key"];
aFlight.timeStamp = [aFlight niceDate:[flight objectForKey:@"timestamp"]];

你总是创建一个ArchiveFlight 的实例并解析时间戳……

    if (![lastFlightno isEqualToString:aFlight.flightno]) {
        [localArray addObject:aFlight];
    }

……即使您不必一直这样做。根据您有多少重复的flightnos,这可能会产生明显的差异。

为什么不阅读[flight objectForKey:@"flightno"],将其与lastFlightno 进行比较,当且仅当它们不同时,创建一个实例,将其添加到数组中,然后释放它?


编辑:尝试以下无 KVC 代码:

NSArray *flights = [deserializedData objectForKey:@"flights"];
NSMutableArray *localArray = [[NSMutableArray alloc] init ];
NSString *lastFlightno =@"";

for (NSDictionary *flightWrapper in flights) {
    NSDictionary *flight = [flightWrapper objectForKey:@"flight"];
    NSString *flightno = [flight objectForKey:@"flightno"];

    if (! [flightno isEqual:lastFlightno]) {
        // create instance, add it to the array, release the instance
    }
}

编辑:您正在此方法中创建和(自动)释放NSDateFormatter 的两个实例。一般来说,这没问题,但由于它被执行 >1K 次,因此有两个考虑因素:a)你正在创建/使用/释放这两个实例 >1K 次,而实际上你没有两个,b ) 你应该在你的循环中使用一个自动释放池。

您应该将此方法设为类方法(或函数),因为它不依赖于该类实例的状态。您的格式化程序将是类(静态)变量。例如:

@implementation ArchiveFlight

static NSDateFormatter *formatter1; // choose better names!
static NSDateFormatter *formatter2;

+ (void)initialize {
    if (self == [ArchiveFlight class]) {
        formatter1 = [[NSDateFormatter alloc] init];
        [formatter1 setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

        formatter2 = [[NSDateFormatter alloc] init];
        [formatter2 setDateStyle:NSDateFormatterFullStyle];
        [formatter2 setTimeStyle:NSDateFormatterLongStyle];
    }
}

+ (NSString *)niceDate:(NSString *)oldDate {
    NSDate *sourceDate = [formatter1 dateFromString:oldDate];
    NSString *timeString = [formatter2 stringFromDate:sourceDate];
    return timeString;
    // why +stringWithFormat:? It’s not necessary!
    // return [NSString stringWithFormat:@"%@",timeString];
}

这修复了 a) 项,但您确实应该在循环中使用自动释放池,因为您使用的 Cocoa 方法返回自动释放的对象。通过为循环的每次迭代使用自动释放池,您可以减少代码的内存占用——尽管这可能也会降低性能。我建议您尝试使用和不使用内部自动释放池。

for (NSDictionary *flightWrapper in flights) {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    …

    [pool drain];
}

【讨论】:

  • 谢谢,我在原始问题中添加了一个 JSON 样本……没有很多重复的航班号,但确实有一个很好的简单修复,可以稍微减少一点!我认为大部分都在KVC上,还有其他方法吗?
  • 谢谢,这有点快。不过现在需要 1.2 秒来执行循环语句。仍然有点太长了,无法理解为什么当通过网络请求和 JSONKit 非常快地完成这一切时!令人困惑!
  • 见上文,这是 niceDate 函数在做的......现在要深入了解它! :-(
  • 如果代码仍然有点慢,我猜 ArchiveFlight 对象的创建“昂贵”,也许你应该看看你是否可以以任何方式优化这个对象。
  • @Lee 又一次!我删除了+stringWithFormat:
猜你喜欢
  • 2022-10-06
  • 2011-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多