通过使用带有ID的已排序NSArray加速循环

时间:2014-07-29 01:00:46

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


我有一个循环通过相当大量的物体的环形循环(目前4000多个,但可能是双倍且不断增长。)
我尝试加速循环,我能够使用自动释放池释放内存并避免应用程序崩溃,但就速度而言,循环非常慢。
有人建议我使用有序数组,但我对编程很新,所以我有点迷失。有人可以分享一些指示吗?

对象" 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];

}

谢谢。

2 个答案:

答案 0 :(得分:5)

执行许多查找的最快方法是将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)];
}

答案 1 :(得分:4)

使用排序数组的优点是可以对其进行二进制搜索,而不是对其进行线性搜索。 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;
}

(您还可以在互联网上找到可以让您更轻松的分类收藏库。)

如果所有你正在检查会员资格,那么,有一个更简单的解决方案:使用NSSet代替NSArray ,或NSDictionaryid映射到其对象。