2

我从头开始学习 iOS 编程。

我希望我的应用程序从网站中提取 XML。我在想,为了符合 MVC 模式,我应该有一个模型类,它只提供一种方法来完成它(也许让它也解析 XML 并返回一个数组)。

问题是我发现的所有教程都在视图和控制器的上下文中教授 NSURLSession - 所以编辑 appdelegate 或创建视图控制器等。

我从 Apples 文档中获得了以下方法,我目前在按下按钮时将它作为 IBAction 运行(因此我可以运行它并轻松测试它)。我想让它工作,然后把它放在它自己的类中:

__block NSMutableData *webData;

NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];

NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
    NSLog(@"Got response %@ with error %@.\n", response, error);
    NSLog(@"DATA:\n%@\nEND DATA\n", [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]);
        webData = [[NSMutableData alloc] initWithData:data];
}
]resume];

我的直接问题是:

有人可以解释完成处理程序是如何工作的以及如何data离开那里吗?它正在工作,数据正在从网站上获取 xml 并将其记录在控制台上,但是将其复制到webData不起作用,它会编译但不会复制。(我仍在弄清楚为什么__block声明webData首先允许潜入那里!)

我更大的问题是,如果每个人都认为为这个过程创建一个单独的模型类的想法是个好主意。有没有更好的设计方法?

谢谢!

4

1 回答 1

2

这可能只是对异步块如何工作的一些混淆。如果你这样做:

__block NSMutableData *webData;
// ...

[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
    NSLog(@"within the block, did I get data: %@", data);
    webData = [[NSMutableData alloc] initWithData:data];
}]resume];

NSLog(@"after the block, did I get data: %@", webData);

您可能会看到如下所示的输出:

after the block, did I get data: (null)
within the block, did I get data: <NSData ...

是什么赋予了?为什么块后的代码先运行?数据在哪里?问题在于我们对“之后”的定义。块之后出现的 NSLog 实际在块运行之前运行。它会在 dataRequest启动后立即运行。块内的代码在请求完成后运行。

将数据结果保存在该方法的本地块变量中对您没有好处。当您到达方法的末尾时,该值未初始化。块在运行时初始化它,但是一旦块完成,该值就会被丢弃。

修复:处理块内的数据。不要期望它在块运行之后才有效(这是在方法运行之后):

编辑- 在这个块中使用 self 来调用方法、设置属性等是 100% 没问题的。只有当块本身是 self 的属性(或自我保留的属性)时,您才需要注意保留周期,这它不是...

// don't do this
//__block NSMutableData *webData;
// ...

[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
    NSLog(@"within the block, did I get data: %@", data);
    NSMutableData *webData = [[NSMutableData alloc] initWithData:data];
    // do whatever you plan to do with web data
    // write it to disk, or save it in a property of this class
    // update the UI to say the request is done

    [self callAMethod:data];     // fine
    [self callAnotherMethod];    // fine
    self.property = data;        // fine
}]resume];

// don't do this, there's no data yet
//NSLog(@"after the block, did I get data: %@", webData);
于 2014-09-19T17:48:58.030 回答