检查初始化它的方法的完成块内的Swift变量的值

时间:2014-10-16 14:47:23

标签: objective-c swift closures objective-c-blocks

在Objective-C中创建NSURLSessionDownloadTask

NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithURL:[NSURL URLWithString:@"google.com"] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
    if (task.state == NSURLSessionTaskStateCompleted) {
        // Do things
    }
}];

[task resume];

我可以在完成模块中访问我正在创建的任务task,也没有问题。

然而,在Swift中,如果我尝试同样的事情:

let URL = NSURL(string: "google.com")
let task = NSURLSession.sharedSession().downloadTaskWithURL(URL, completionHandler: { location, response, error in
    if task.state == .Completed {
        // Do things
    }
}

task.resume()

我可以错误地说“变量正在其自己的初始值中使用”。

我该如何规避这个?

3 个答案:

答案 0 :(得分:3)

更新回答 我现在意识到我没有仔细阅读你的代码。您没有将闭包传递给初始化器,而是传递给方法。在将闭包传递给初始化程序时,我最初编写的内容仍然有效,但不是在你的情况下。

你的问题很相似。

您有一个task变量,该变量使用函数的返回值进行初始化。您将闭包传递给函数,并在闭包内引用task变量。

编译器不知道关闭何时执行(至少我认为它不会检查它,它是downloadTaskWithURL()内部实现细节) - 它&#39 ;它可能在函数体中执行(而不是将它存储在属性中并在以后执行)。如果闭包是在函数体中执行的,那么当它尚未被赋值时它将访问task变量(因为该函数仍在执行)。

如果有一种方法让编译器知道闭包没有在函数体中执行,那么编译器就可以处理这种情况。但斯威夫特并没有实现这样的目标。

结论:我很感激编译器为此抛出一个错误,因为否则我会期待一个运行时异常 - 尽管可能不是在你的特定情况下(因为后面会执行闭包)。

原始回答

正如您可能知道的那样,在所有类/结构属性都已正确初始化并且已调用基本初始化程序(对于继承的类)之前,swift self不可用

您正在将闭包传递给类初始化程序 - 编译器无法确定何时执行闭包,因此闭包本身不能包含对self的任何(直接或间接)引用。

在您的情况下,task是要实例化的变量,因此当您在闭包中使用它时,就像您使用self一样。这是不允许的,所以你有错误。

在Objective C中没有发生同样的事情,因为初始化器中没有这样的约束。

但请注意,从概念上讲,你所做的并不是一个好习惯。您正在读取之前的类实例的属性已正确初始化。要确定调用的状态,您应该依赖传递给闭包的参数,理想情况下应该提供您需要的所有信息。

答案 1 :(得分:0)

您的task.state尚未初始化但有一些价值。您正在尝试在类实例初始化之前读取它们的属性。

答案 2 :(得分:0)

现在,我能够解决这个问题的唯一方法是在初始化程序之前声明变量,然后在闭包内部访问它:

let URL = NSURL(string: "google.com")
var task: NSURLSessionTask?
task = NSURLSession.sharedSession().downloadTaskWithURL(URL, completionHandler: { location, response, error in
    if task?.state == .Completed {
        // Do things
    }
}

task?.resume()