首页 > 解决方案 > 在objective-c的块内保留分配的值

问题描述

我正在尝试创建一个实现自定义隧道协议的应用程序。并且在从块中为变量赋值时遇到问题,请参见以下代码

@implementation ProfileTableViewController{
     __block NSArray *vpnProfiles;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.allowsMultipleSelectionDuringEditing = NO;
[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray* newManagers, NSError *error)
     {
         if(error != nil){
             NSLog(@"Load Preferences error: %@", error);
         }else{

             if([newManagers count] > 0)
             {
                 vpnProfiles = newManagers;
                 NSLog(@"vpnProfiles 1st: %ld", [vpnProfiles count]);
             }
         }
     }];

 NSLog(@"vpnProfiles 2nd: %ld", [vpnProfiles count]);
}

以上将打印

vpnProfiles 2nd: 0
vpnProfiles 1st: 1

我的理解是这个问题是由于异步线程造成的,但是在搜索和尝试之后我似乎无法找到解决方案。

有人对如何将newManagers获取到局部变量vpnProfiles有建议吗?

标签: objective-cobjective-c-blocks

解决方案


首先,代码中对__block限定符的用途存在误解。

此限定符仅适用于局部变量(请参阅块的语言规范中__block存储限定符),因为它的目的是延长局部变量的生命周期,如果它们可以被块修改,一旦方法/函数/语言-阻止它们在出口中定义。

代码vpnProfiles中是一个实例变量,它的生命周期与其所属对象实例的生命周期相关联,__block因此没有任何意义——不幸的是,编译器并没有警告你,只是忽略了它。实例变量可以被块捕获和修改,因为这样做也会捕获拥有的对象实例,因此通常(†)在块引用它时使其保持活动状态。

现在是主要问题和评论:

我的理解是这个问题是由于异步线程

确切地。

您的loadAllFromPreferencesWithCompletionHandler:方法接受一个完成处理程序,它可能会在它返回的方法之后的某个时间运行......

因此,在调用之后执行NSLog块内- 正如问题中显示的输出所示。NSLogloadAllFromPreferencesWithCompletionHandler:

有人对如何获取newManagers本地实例 变量有建议vpnProfiles吗?

它已经被语句赋值了vpnProfiles = newManagers;——问题是代码在赋值发生之前检查它。

但我似乎找不到解决方案

线索在您的方法的名称中,该块是一个完成处理程序,将在将来的某个时间newManagers可用时调用。在此完成处理程序中,您需要安排该点之后执行的工作。

因此,例如,您可以分配给vpnProfiles然后使用dispatch_async()来调度一个块,该块调用您ProfileTableViewController实例上的一个方法,该方法读取vpnProfiles并执行所需的任何操作。

我正在尝试创建一个实现自定义隧道协议的应用程序。

现在是进一步研究异步设计方法的时候了,因为它对于此类代码至关重要。玩得开心!

高温高压

笔记

(†) 如果捕获的对象引用很弱,则对象不会保持活动状态。了解更多关于这项研究的“参考周期”和“弱自我”。


推荐阅读