2014-03-29 21 views
-1

我有一个执行web服务调用的块的队列。问题是在块结束后下载的数据没有被释放。我读了很多关于保留的内容,但是我无法让ARC去分配内存。如何避免Objective-C中的块保留

下面的代码:

  1. 创建块,其下载数据

    - (void)syncData 
    { 
        dispatch_semaphore_t sema = dispatch_semaphore_create(0); 
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); 
    
        dispatch_async(queue, ^{ 
    
         [Model syncAziende:^(id response, NSError *error) { 
          dispatch_semaphore_signal(sema); 
         }]; 
         dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
    
         [Model syncContatti:^(id response, NSError *error) { 
          dispatch_semaphore_signal(sema); 
         }]; 
         dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
    
         [Model syncDestinazioni:^(id response, NSError *error) { 
          dispatch_semaphore_signal(sema); 
         }]; 
         dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
    
         and so on... 
    
        }); 
    } 
    
  2. 在Model.m

    + (void)syncAziende:(RequestFinishBlock)completation 
    { 
        __weak typeof(self)selfObject = self; 
    
        [selfObject syncData:^(id response, NSError *error) { 
         completation(response,error); 
        } wsEndPoint:kCDCEndPointGetAziende tableName:kCDCDBAziendeTableName]; 
    } 
    
    + (void)syncContatti:(RequestFinishBlock)completation 
    { 
        __weak typeof(self)selfObject = self; 
    
        [selfObject syncData:^(id response, NSError *error) { 
         completation(response,error); 
        } wsEndPoint:kCDCEndPointGetContatti tableName:kCDCDBContattiTableName]; 
    } 
    
    // and so on... 
    
  3. 哪里syncData是队列:

    + (void)syncData:(RequestFinishBlock)completation wsEndPoint:(NSString*) url tableName:(NSString *)table 
    { 
        __weak typeof(self)selfObject = self; 
    
        [selfObject getDataFromWS:^(id WSresponse, NSError* WSError) 
        { 
         completation(nil,nil); 
        }WSUrl:url]; 
    } 
    
  4. 其中getDataFromWS是:

    + (void)getDataFromWS:(RequestFinishBlock)completation WSUrl:(NSString *)svcUrl 
    { 
        __weak typeof(self)selfObject = self; 
        [selfObject getJsonDataFromURL:^(id response, NSError *error) 
        { 
         completation(response,error); 
        }url:svcUrl]; 
    } 
    
  5. 其中​​是:

    +(void)getJsonDataFromURL:(RequestFinishBlock)completation url:(NSString*)url 
    { 
        __weak typeof(self)selfObject = self; 
    
        __weak AFHTTPRequestOperationManager *manager = [selfObject getAuthorizedRequestionOperationManager]; 
    
        [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, __weak id responseObject) { 
         completation([responseObject objectForKey:@"d"],nil); 
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
         completation(nil,error); 
        }]; 
    } 
    
+3

请将代码粘贴到您的问题中。 https://meta.stackexchange.com/questions/80978/questions-linking-to-external-web-sites-instead-of-showing-code –

+0

尝试使用__block作为下载的数据。 –

+0

@KingMingLin究竟在哪里? – user3463206

回答

0

这些__weak引用并不真正使一类方法的上下文中的意义。在处理实例方法时,使用weak - self模式才有意义。

因此,这引发了一个问题,即您担心哪些对象没有获得释放。我在这里没有看到任何会导致保留syncData作为实例方法的对象。 (a)保留在整个过程中实例化的任何自动释放对象(特别是操作本身);以及(b)保留在整个过程中实例化的任何自动释放对象。 (b)一旦开始就不允许您取消流程;和(c)连续运行这些请求(为此你将付出严重的性能损失,除非你绝对必须避免这种惩罚)。

我建议简化代码。我会用信号消除调度代码。我也摆脱所有weak引用self在课堂上的方法。

您应该简单地发出您的GET请求。如果您真的需要它们串行运行(如您使用信号量所暗示的那样),那么只需将maxConcurrentOperationCount设置为1即可获得AFHTTPRequestOperationManager实例的operationQueue。但是,除非你绝对必须,否则不要让它们连续运行,因为这样做会使性能受到严重损失。但利用AFNetworking提供的NSOperationQueue,而不是自己做GCD代码(更糟糕的是,使用GCD代码中的信号量)。

但是通过这种方式,如果您想取消请求,您可以拨打cancelAllOperations来获得AFHTTPRequestOperationManageroperationQueue。您还可以使用maxConcurrentOperationCount来控制并发程度。

+0

感谢您提供有用的信息,但它不能回答我的问题。 – user3463206

+1

@ user3463206也许我不清楚:我认为当你使用信号量同步分派一系列长请求时,你可能会不必要地保留对象。这就是为什么我建议你摆脱这种构造。 – Rob

+0

pastie.org/8979057为什么ARC dealloc(为什么不是所有下载的对象???)在队列的末尾? – user3463206

0

鉴于你的描述,并根据该意见,一个天真的 - 但仍然不够 - 的解决方案可能会是这样:

//一个通用完成处理: 无效的typedef(^ completion_t)(ID结果,NSError *错误);

- (void) fetchJSONFromURL:(NSURL*)url completion:(completion_t)completion; 

- (void) syncAziendeWithInput:(id)input completion:(completion_t)completion; 

- (void) syncContattiWithInput:(id)input completion:(completion_t)completion; 

- (void) syncDestinazioniWithInput:(id)input completion:(completion_t)completion; 



- (void) syncData 
{ 
    dispatch_queue_t sync_queue = dispatch_queue_create("sync_queue", 0); // serial queue 

    NSURL* url = ...; 
    [self fetchJSONFromURL:url completion:^(id result, NSError*error){ 
     dispatch_async(sync_queue, ^{ 
      [self syncAziendeWithInput:result completion:^(id result, NSError* error){ 
       ... 
      }]; 
     }); 
    }]; 

    url = ...; 
    [self fetchJSONFromURL:url completion:^(id result, NSError*error){ 
     dispatch_async(sync_queue, ^{ 
      [self syncContattiWithInput:result completion:^(id result, NSError* error){ 
       ... 
      }]; 
     }); 
    }]; 

    url = ...; 
    [self fetchJSONFromURL:url completion:^(id result, NSError*error){ 
     dispatch_async(sync_queue, ^{ 
      [self syncDestinazioniWithInput:result completion:^(id result, NSError* error){ 
       ... 
      }]; 
     }); 
    }]; 


    ... 
} 

注意事项:

简单化。一个实际的解决方案变得更加详细:

  • 没有错误处理呢。

  • 无法取消异步任务。

  • syncData是异步的,但没有完成处理程序。也就是说,我们不知道它何时完成。我们可以利用dispatch_group来实现一种方法来表示一些异步方法的完成。

在第三方库的帮助下,我们可以实现一个解决方案,它可以完成上述所有功能,而且看起来基本上更简单。