从目标c

时间:2019-07-17 15:54:23

标签: objective-c objective-c-blocks

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

@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 的建议吗?

1 个答案:

答案 0 :(得分:1)

首先,代码中对Y限定词的用途有误解。

此限定符仅适用于局部变量(请参见块语言规范中的The __block Storage Qualifier),因为其目的是延长局部变量的寿命(如果它们可以被块修改),一旦在出口中定义了方法/功能/语言块,它们就会消失。

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

现在要问的主要问题和评论:

  

我的理解是此问题是由于异步线程引起的

完全正确。

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

因此,在调用__block之后的loadAllFromPreferencesWithCompletionHandler:之后的之后执行该块中的NSLog –如问题所示的输出所示

  

有人对如何获取NSLog local instance 变量loadAllFromPreferencesWithCompletionHandler:的建议吗?

它已经由语句newManagers分配了-问题是代码在 发生之前正在检查分配。

  

但是我似乎找不到解决方法

线索就在您的方法名称中,该块是一个补全处理程序,它将在将来的vpnProfiles可用时被调用。您需要在此完成处理程序内 安排在该点之后 要做的工作。

例如,您可以对vpnProfiles = newManagers;进行赋值,然后使用newManagers安排一个块,该块在您的vpnProfiles实例上调用读取dispatch_async()的方法并做任何需要的事情。

  

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

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

HTH

注意

(†)如果捕获的对象引用是 weak ,则该对象不会保持活动状态。要了解有关此研究的更多信息,请参见“参考周期”和“弱自我”。