使用块时ARC不会释放内存

时间:2014-03-28 13:40:06

标签: ios objective-c memory-management automatic-ref-counting

我遇到ARC问题。 我所做的是同步:我从webservice请求数据,然后将其写入数据库(使用fmdb)。

这是我的完整代码

dispatch_async(queue, ^{

    hud.labelText = [NSString stringWithFormat:@"Sincronizzo le aziende"];
    [Model syncAziende:^(id response, NSError *error) {
        hud.progress += offset;
        dispatch_semaphore_signal(sema);
    }];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

    hud.labelText = [NSString stringWithFormat:@"Sincronizzo i contatti"];
    [Model syncContatti:^(id response, NSError *error) {
        hud.progress += offset;
        dispatch_semaphore_signal(sema);
    }];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

            ....

+ (void)syncAziende:(RequestFinishBlock)completation
{
    [self syncData:^(id response, NSError *error) {
        completation(response,error);
    } wsEndPoint:kCDCEndPointGetAziende tableName:kCDCDBAziendeTableName];
}

+ (void)syncData:(RequestFinishBlock)completation wsEndPoint:(NSString*) url tableName:(NSString *)table
{
    NSLog(@"%@",url);
    [self getDataFromWS:^(id WSresponse, NSError* WSError)
     {
         if (!WSError)
             [self writeDatatoDB:^(id DBresponse,NSError* DBError)
              {
                  completation(DBresponse,DBError);
              }table:table shouldDeleteTableBeforeUpdate:YES data:WSresponse];
         else
             completation(nil,WSError);
         WSresponse = nil;
     }WSUrl:url];
}

+ (void)getDataFromWS:(RequestFinishBlock)completation WSUrl:(NSString *)svcUrl
{
    [self getJsonDataFromURL:^(id response, NSError *error)
     {
         completation(response,error);
     }url:svcUrl];
}

+(void)getJsonDataFromURL:(RequestFinishBlock)completation url:(NSString*)url
{
    AFHTTPRequestOperationManager *manager = [self getAuthorizedRequestionOperationManager];

    if (manager) { //OK I'have internet connection
        [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        [manager.requestSerializer setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];

        [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
            completation([responseObject objectForKey:@"d"],nil);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            completation(nil,error);
        }];
    }
    else //ERROR: I don't have internet connection
    {
        NSDictionary *dError = [[NSDictionary alloc] initWithObjectsAndKeys:kCDCErrorNoInternetConnectionStatusMessage,@"error", nil];
        NSError *error = [[NSError alloc]initWithDomain:url code:kCDCErrorNoInternetConnectionStatusCode userInfo:dError];
        completation(nil,error);
    }
}


+ (void) writeDatatoDB:(RequestFinishBlock)completion
                 table:(NSString *)tableName
shouldDeleteTableBeforeUpdate:(BOOL)deleteTable
                  data:(NSMutableArray *)data
{
    NSLog(@"Inizio le operazioni sul database");
    __block int errors = 0;

    classAppDelegate *appDelegate = (classAppDelegate *)[[UIApplication sharedApplication]delegate];
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:appDelegate.dbFilePath];
    [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {

        if (deleteTable)
            [db executeUpdate:[NSString stringWithFormat:@"DELETE FROM %@", tableName]];

        for (NSDictionary *jString in data)
        {
            NSMutableArray* cols = [[NSMutableArray alloc] init];
            NSMutableArray* vals = [[NSMutableArray alloc] init];

            for (id currentValue in jString)
            {
                if (![currentValue isEqualToString:@"__metadata"]) {
                    [cols addObject:currentValue];
                    [vals addObject:[jString valueForKey:currentValue]];
                }
            }

            NSMutableArray* newCols = [[NSMutableArray alloc] init];
            NSMutableArray* newVals = [[NSMutableArray alloc] init];
            NSString *value = @"";

            for (int i = 0; i<[cols count]; i++) {
                @try {
                    NSString *element = [vals objectAtIndex:i];
                    if (![element isKindOfClass:[NSNull class]]) {
                        value = [element stringByReplacingOccurrencesOfString:@"'" withString:@"''"];
                        [newCols addObject:[NSString stringWithFormat:@"'%@'", [cols objectAtIndex:i]]];
                        [newVals addObject:[NSString stringWithFormat:@"'%@'", value]];
                    }
                }
                @catch (NSException *exception) {

                }
            }

            NSString* sql = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)",tableName, [newCols componentsJoinedByString:@", "], [newVals componentsJoinedByString:@", "]];
            [db executeUpdate:sql];

            if([db lastErrorCode] == 1) //ERRORE!!
            {
                errors++;
            }
        }
        completion(nil,nil);


        NSLog(@"Ho completato le operazioni sul database con %i errori",errors);
    }];
}

我从webservice获得的数据大约是75mb,但在Xcode中,我看到内存达到了500mb,这使iPad 2崩溃。

2 个答案:

答案 0 :(得分:3)

你确实在你的街区中做了保留周期

它主要发生在你在街区调用自我时。因此,自我保留在块和主序列中。所以两者都相互支持,ARC认为另一方都需要它们。

你应该使用弱自我或类似的其他方法。

这里有一些帮助:The Correct Way to Avoid Capturing Self in Blocks With ARC

答案 1 :(得分:0)

libextobjc有一些有用的宏来帮助解决这个问题,请参阅http://aceontech.com/objc/ios/2014/01/10/weakify-a-more-elegant-solution-to-weakself.html