模型、块和完成处理程序 Oh MY
Posted
技术标签:
【中文标题】模型、块和完成处理程序 Oh MY【英文标题】:Models, blocks and completion handlers Oh MY 【发布时间】:2014-09-19 15:37:40 【问题描述】:我从零开始学习 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
首先潜入那里!)
我更大的问题是,如果每个人都认为为这个过程创建一个单独的模型类的想法是个好主意。有没有更好的设计方法?
谢谢!
【问题讨论】:
也许你在查找 ***.com/questions/22609434/…>。那里的答案可能会提示您出了什么问题。 我看过那个页面。我已经在使用委托免费会话,所以我不确定它是如何适用的......另外,我的完成处理程序正在执行,我只是不知道如何从中获取数据。 “复制”是什么意思? 我的意思是webData = [[NSMutableData alloc] initWithData: data];
不会将信息从data
复制到webData
。我想按值传递,我认为这就是 initWithData
会做的事情。
【参考方案1】:
这可能只是对异步块如何工作的一些混淆。如果你这样做:
__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);
【讨论】:
我试图在块之后(之前)对其进行 NSLog。我不明白的是,如果我不能在块中使用类属性,如何将它保存在类的属性中?那有意义吗?对不起,如果这应该是显而易见的,但我对此真的很陌生 所以,我设法在块中将data
解析为一个对象数组(甚至不需要webData
。现在我如何将该数组从块中取出并返回给调用者?
@MayNotBe - 您可以在该块中放置您希望的任何代码。您通常放入方法中的任何内容都可以。见编辑。
谢谢。我明白。我想我的麻烦是即使我可以做到 [self.property = data]
,self.property
在我需要的时候仍然是空的,无论我如何尝试,我都没有弄清楚如何“赶上”。
属性是否声明为@property(strong, nonatomic) NSData *property;
?以上是关于模型、块和完成处理程序 Oh MY的主要内容,如果未能解决你的问题,请参考以下文章
iTerm2 + oh-my-zsh 教程(7000字长文)