我从零开始学习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
首先潜入那里!)
我更大的问题是,如果每个人都认为这个过程的单独模型类的想法是个好主意。有没有更好的设计方法?
谢谢!
答案 0 :(得分: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 ...
是什么给出的?为什么块之后的代码首先运行?数据在哪里?问题出在我们对&#34;&#34;之后的定义。块之后出现的NSLog实际在块运行之前运行。一旦dataRequest 启动,它就会立即运行。在请求完成之后,块内的代码会运行。
将数据结果保存在该方法的本地块变量中对您没有好处。当您点击方法结束时,该值未初始化。块在块运行时初始化它,但块一旦完成就会丢弃该值。
修复:处理块内的数据。不要期望它在块运行之后才有效(在方法运行之后很久):
编辑 - 在此块中使用self调用方法,设置属性等是100%罚款。只有当块本身是一个时,才需要注意保留周期自我的财产(或自我保留的财产),它不是......
// 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);