__unsafe_unretained导致消息发送到解除分配的实例

时间:2012-12-10 21:31:04

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

我正在使用块来执行与网络相关的任务

当块在我的UITableViewController中完成时,我想重新加载tableviewcontroller

__unsafe_unretained UITableView *unretTableView = self.tableview;

[myRequest postWithCompletion:(bool finished) {
    [unretTableView reloadData];
}];

这很好,除非我在请求完成之前离开(deallocateUITableViewController我似乎指向一个解除分配的对象(unretTableView消息发送到解除分配的实例,即使在[UITableViewController dealloc]方法(正在调用)中,我设置了self.tableview = nil;

其他详情:

  • 无法使用__weak,我定位的是iOS 4.3及以上版本
  • UITableViewController的{​​{1}}方法中,我设置dealloc
  • 我不想在你离开页面时取消网络请求,我希望它继续运行。
  • 编辑:我不想在块中保留self.tableview

谢谢!

4 个答案:

答案 0 :(得分:1)

鉴于您的意见,我可能倾向于追求NSOperationQueue。这样你就可以

  1. 创建背景NSOperationQueue;

  2. 如果您的下载允许一定数量的同时下载,您可以设置maxOperationCount(或者如果您想要连续下载,请将其设置为1)。

  3. 当您启动后台作业时,您可以创建NSOperation个对象,或者直接通过addOperationWithBlock通过块提交NSOperationQueue。如果您希望能够检查isCancelled标志,则可能需要执行前者。

  4. 在尝试更新视图控制器之前,每个操作都可以检查是否已取消。

  5. 当视图控制器被解除时,它可以执行简单的cancelAllOperations来取消排队的所有内容。

  6. 这是一个随机的例子:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.queue = [[NSOperationQueue alloc] init];
        self.queue.maxConcurrentOperationCount = 4;
    
        // let's add 100 operations to our queue
    
        for (NSInteger i = 0; i < 100; i++)
        {
            NSBlockOperation *operation = [[NSBlockOperation alloc] init];
            __unsafe_unretained NSBlockOperation *weakOperation = operation; // it seems vaguely disturbing to do this with __unsafe_unretained, but given that the operation queue is taking care of this for us, I believe it's ok
            [operation addExecutionBlock:^{
    
                NSLog(@"Beginning operation %d", i);
    
                sleep(10);
    
                if ([weakOperation isCancelled])
                    NSLog(@"Operation cancelled %d", i);
                else
                {
                    // go ahead and update UI if you want
                    NSLog(@"Finished operation %d", i);
                }
            }];
    
            [self.queue addOperation:operation];
        }
    }
    
    - (void)viewDidDisappear:(BOOL)animated
    {
        [super viewDidDisappear:animated];
        [self.queue cancelAllOperations];
    }
    

答案 1 :(得分:0)

稍后将属性设置为与块所捕获的变量设置的内容无关。如果要访问该属性,则需要访问属性:self.foo,而不是foo。

请注意,在这种情况下您仍需要小心,因为在块中捕获self会导致自我保留,这可能会导致保留周期。

(编辑) 如果你从另一个线程更新属性,这仍然是不安全的。您需要某种形式的序列化结构才能使其安全(NSLock,NSOperationQueue,dispatch_queue_t等等)。我假设这不是线程,但万一它是,这很重要。

答案 2 :(得分:-1)

试试这个:

__block __unsafe_unretained UITableView *unretTableView = self.tableview;

修改

我不知道您使用什么框架发布请求。但是当您使用 [myRequest postWithCompletion:yourBlock] 发布请求时,我认为还有一种方法可以更改完成块,类似 myRequest.completion = nil

答案 3 :(得分:-2)

插入完整性检查。

__weak UITableView *table = unretTableView;
if (table) [unretTableView reloadData];