【问题标题】:Speed up for loop by using sorted NSArray with ids通过使用带 id 的排序 NSArray 来加速 for 循环
【发布时间】:2014-07-29 01:00:45
【问题描述】:


我有一个循环遍历大量对象的 foo 循环(目前 4000 多个,但可能是双倍的并且还在增长。

我正在尝试加快周期,我能够使用 autoreleasepool 释放内存并避免应用程序崩溃,但就速度而言,周期非常慢。
有人建议我使用有序数组,但我对编程很陌生,所以我有点迷茫。有人可以分享一些方向吗?

“Sede”中的对象具有渐进式 ID

这是我的代码:

NSArray *sedi = [Sede sedeArray];
for (Sede *sedeTmp in sedi)
        {
            @autoreleasepool {
                if (sedeTmp.idSede == idSede)
                {
                    sede = sedeTmp;
                    break;
                }
            }
        }

这是我的完整代码:

+ (void)importData:(NSDictionary *)data
{
    NSArray *info = data[@"Info"];
    if (info != (id)[NSNull null])
    {

    }

    NSMutableArray *utenti = [NSMutableArray arrayWithArray:[Utente utenteArray]];
    NSMutableArray *utentiNew = [[NSMutableArray alloc] init];
    for (NSDictionary *utenteWS in data[@"Utenti"])
    {
        NSInteger stato = [(NSNumber *)[NSString decrypt:utenteWS[@"Stato"]] integerValue];
        NSInteger idUtente = [(NSNumber *)[NSString decrypt:utenteWS[@"IDUtente"]] integerValue];
        Utente *utente = nil;
        for (Utente *utenteTmp in utenti)
        {
            if (utenteTmp.idUtente == idUtente)
            {
                utente = utenteTmp;
                break;
            }
        }
        if (stato == 2) //DELETE
        {
            if (utente)
        {
            [self setUtente:utente fromUtenteWS:utenteWS];
            utente.eliminato = YES;
        }
        continue;
    }
    if (!utente)
    {
        utente = [Utente utente:(int)idUtente];
        [utentiNew addObject:utente];
    }
    [self setUtente:utente fromUtenteWS:utenteWS];
}
[BOTManagedObjectContext save];

[utenti addObjectsFromArray:utentiNew];
NSArray *sedi = [Sede sedeArray];
NSMutableArray *sediDel = [[NSMutableArray alloc] init];
NSMutableArray *contattiDel = [[NSMutableArray alloc] init];
for (NSDictionary *sedeWS in data[@"Sedi"])
{
    NSInteger statoSede = [(NSNumber *)[NSString decrypt:sedeWS[@"Stato"]] integerValue];
    long long idSede = [(NSNumber *)[NSString decrypt:sedeWS[@"IDSede"]] longLongValue];
    Sede *sede = nil;


    NSArray *sedeArray = [Sede sedeArray];
    NSMutableDictionary *itemsByItemID = [NSMutableDictionary dictionary];
    for (Sede *sede in sedeArray) {
        itemsByItemID[@(sede.idSede)] = sede;
    }
    self.sedesBySedeID = itemsByItemID;



    //for loop is too slow
    /*for (Sede *sedeTmp in sedi)
    {
        @autoreleasepool {
            if (sedeTmp.idSede == idSede)
            {
                sede = sedeTmp;
                break;
            }
        }
    }*/
    //end of guilty for loop

    if (!sede)//if enters here, local db is empty
    {
        if (statoSede == 2) //DELETE
            continue;

        sede = [BOTManagedObjectContext insertNewObjectForEntityForName:@"Sede"];
        sede.idSede = idSede;
        NSInteger idUtente = [(NSNumber *)[NSString decrypt:sedeWS[@"IDUtente"]] integerValue];
        for (Utente *utente in utenti)
        {
            if (utente.idUtente == idUtente)
            {
                sede.utente = utente;
                break;
            }
        }
        for (NSDictionary *contattoWS in sedeWS[@"Contatti"])
        {
            if ([(NSNumber *)[NSString decrypt:contattoWS[@"Stato"]] integerValue] == 2) continue;

            Contatto *contatto = [BOTManagedObjectContext insertNewObjectForEntityForName:@"Contatto"];
            contatto.sede = sede;
                [self setContatto:contatto fromContattoWS:contattoWS];
            }

            [self setSede:sede fromSedeWS:sedeWS];
        }
        else
        {
            if (statoSede == 2 && !sede.tour) //DELETE
            {

                [sediDel addObject:sede];
                for (Contatto *contatto in sede.contattoCollection)
                {
                    [contattiDel addObject:contatto];
                }
                continue;
            }

            for (NSDictionary *contattoWS in sedeWS[@"Contatti"])
            {
                NSInteger statoContatto = [(NSNumber *)[NSString decrypt:contattoWS[@"Stato"]] integerValue];
                BOOL find = NO;
                long long idContatto = [(NSNumber *)[NSString decrypt:contattoWS[@"IDContatto"]] longLongValue];
                for (Contatto *contatto in sede.contattoCollection)
                {
                    if (contatto.idContatto == idContatto)
                    {
                        find = YES;
                        if (statoContatto == 2) //DELETE
                        {
                            [contattiDel addObject:contatto];
                        }
                        else
                        {
                            [self setContatto:contatto fromContattoWS:contattoWS];
                        }
                        break;
                    }
                }
                if (!find)
                {
                    if (statoContatto == 2) //DELETE
                        continue;

                    Contatto *contatto = [BOTManagedObjectContext insertNewObjectForEntityForName:@"Contatto"];
                    contatto.sede = sede;
                    [self setContatto:contatto fromContattoWS:contattoWS];
                }
            }
            //controllo se ci sono contatti non presenti nel ws e in caso li elimino
            for (Contatto *contatto in sede.contattoCollection)
            {
                BOOL find = NO;
                for (NSDictionary *contattoWS in sedeWS[@"Contatti"])
                {
                    long long idContatto = [(NSNumber *)[NSString decrypt:contattoWS[@"IDContatto"]] longLongValue];
                    if (contatto.idContatto == idContatto)
                    {
                        find = YES;
                        break;
                    }
                }
                if (!find)
                {
                    [contattiDel addObject:contatto];
                }
            }

            [self setSede:sede fromSedeWS:sedeWS];
            if (statoSede == 2 && sede.tour)
                sede.eliminata = YES;
        }
    }
    [BOTManagedObjectContext save];

    for (Contatto *contatto in contattiDel)
    {
        [BOTManagedObjectContext deleteObject:contatto];
    }
    [BOTManagedObjectContext save];

    for (Sede *sede in sediDel)
    {
        [BOTManagedObjectContext deleteObject:sede];
    }
    [BOTManagedObjectContext save];

}

谢谢。

【问题讨论】:

  • 使用 NSDictionary 而不是 NSArray。

标签: ios objective-c performance for-loop nsarray


【解决方案1】:

执行 许多 查找的最快方法是将您的 NSArray 转换为 NSDictionary。此初始转换将花费线性时间,这与当前循环花费的时间相同。 然而,未来的查找将只需要固定的时间!

NSArray *sedeArray = [Sede sedeArray];
NSMutableDictionary *itemsByItemID = [NSMutableDictionary dictionary];
for (Sede *sede in sedeArray) {
    itemsByItemID[@(sede.idSede)] = sede;
}
self.sedesBySedeID = itemsByItemID;

这个方法只需要固定的时间来找到你的对象。

- (Sede *)sedeForSedeID:(int)sedeID {
    return self.sedesBySedeID[@(sedeID)];
}

【讨论】:

  • 谢谢。 sedesBySedeID 是什么属性?
  • 您班级中的一个属性。你需要一些方法来保存字典。什么是 Sede?​​span>
  • Sede 是包含多个 NSString 的 ManagedObject
  • @property (copy, nonatomic) NSDictionary *sedesBySedeID;那么呢?
  • 根据您的需要复制或加强作品。如果您不知道,您应该查找差异。
【解决方案2】:

使用排序数组的优点是您可以对它进行二进制搜索,而不是对其进行线性搜索。 Wikipedia 对算法的描述非常好。

要做到这一点,你从中间开始,然后,如果你没有找到值,检查你是否太高或太低,然后向相反的方向跳到一半。最终,您会找到该值,或者“中途”将是 0 步并且您知道它不存在。

这足以让您入门。

NSUInteger findInSortedArray(NSArray *arr, id obj) {
    NSUInteger low = 0;
    NSUInteger high = arr.count;
    while (low + 1 < high) {
        NSUInteger mid = (low + high) / 2;
        if ([arr[mid] isEqual:obj]) return mid;
        // ..
    }
    return -1;
}

(您还可以在 Internet 上找到分类收藏库,这将使您更轻松。)

如果所有您正在检查成员资格,但是,还有一个更简单的解决方案:使用NSSet 而不是NSArray,或使用NSDictionary 映射每个@987654326 @ 到它的对象。

【讨论】:

  • 感谢您让我更清楚。但是我不确定我是否能够在代码中翻译它。我应该如何进行?非常感谢。
  • @DavideC:我给了你一半的代码,还有一个维基百科文章的链接,该文章的代码是用 C 编写的,也有其他实现的链接。 (维基百科还包括一个秘密捷径,它可以让你的生活更轻松,在你了解二分搜索的全部内容之前,我不想给你。)试着自己写;如果遇到困难,可以提出具体问题。
  • 谢谢。我之前的评论是关于您在编辑之前的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2021-09-03
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多