2014-10-16 18 views
2

拿在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,在完成块内也没有问题。

然而,斯威夫特,如果我尝试同样的事情:

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() 

我可以在“变量被其自身的初始值内使用”的错误。

我如何绕过这个?

+0

“我可以访问非常任务我创建,任务,在完成块内也没有问题。“不,你不能,而不是那个代码。任务'应该始终是'nil'或该块内的垃圾。由于'task'不是'__block',所以当块被创建时,该块将捕获'task'的值,这是在下载任务被分配给它之前。 – newacct 2014-10-16 20:02:24

回答

3

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

虽然你的问题是类似的。

您有一个task变量,它用函数的返回值初始化。你传递一个闭包给函数,并且在闭包内引用task变量。

编译器不知道什么时候执行了闭包(至少我不认为它会检查它,它是一个downloadTaskWithURL()内部实现细节) - 并且它有可能在函数体中执行(相反将其存储在一个属性中并在稍后执行)。如果闭包在函数体中执行,那么当它尚未被赋值时(因为函数仍在执行),它将访问变量task

如果有方法让编译器知道函数体中没有执行闭包,那么编译器可以处理这种情况。但迅捷并没有实现类似的东西。结论:我很欣赏编译器为此抛出一个错误,因为否则我会期待一个运行时异常 - 尽管可能不在您的特定情况下(因为稍后会执行闭包)。

原来的答复

正如你可能知道,在迅速self是不可用的,直到所有的类/结构性质已被正确初始化,以及基础初始化被称为(对于继承类)

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

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

目标C中不会发生这种情况,因为初始化程序中没有这样的约束。

但是请注意,从概念上讲,您正在做的事情看起来不太好。您正在读取类别实体的属性,然后已正确初始化。要确定调用的状态,您应该依靠传递给闭包的参数,理想情况下应提供所需的所有信息。

+0

完成块只会在初始化后触发吗?没有一种沉默的保证? – 2014-10-16 15:14:41

+0

你是对的,我误解你的代码 - 看到更新的答案 – Antonio 2014-10-16 15:24:10

+0

阻止 - 我想我犯了另一个错误...更新答案... – Antonio 2014-10-16 15:30:05

0

你的task.state还没有被启发,但有一些价值。您正试图在初始化之前读取类实例的属性。

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()