Iphone 在类/异步请求/iOS之间传递数据
我正在将我的应用程序从同步HTTP请求转换为异步HTTP请求,并且遇到了一个问题,看起来它需要对应用程序处理数据的方式进行大量修改。让我试着解释一下 以前是这样的,Iphone 在类/异步请求/iOS之间传递数据,iphone,ios,objective-c,ipad,oop,Iphone,Ios,Objective C,Ipad,Oop,我正在将我的应用程序从同步HTTP请求转换为异步HTTP请求,并且遇到了一个问题,看起来它需要对应用程序处理数据的方式进行大量修改。让我试着解释一下 以前是这样的, //Get user input data = [helperclass makerequest] sendData = [data process] //Get user input data = [helperclass makerequestWithSuccess:^{ sendData = [data proces
//Get user input
data = [helperclass makerequest]
sendData = [data process]
//Get user input
data = [helperclass makerequestWithSuccess:^{
sendData = [data process]
}];
-(void)makerequestWithSuccess:(void (^)(void))success{
// Put your makerequest code here
// After your makerequest is completed successfully, call:
success();
}
typedef (void)(^completion_block_t)(id result);
-(void) asyncTaskA:(completion_block_t)completionHandler;
-(void) asyncTaskBWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncTaskCWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler
{
[self asyncTaskA:^(id resultA){
if (![resultA isKindOfClass:[NSError class]]) {
[self asyncTaskBWithInput:resultA completion:^(id resultB){
if (![resultB isKindOfClass:[NSError class]]) {
[self asyncTaskCWithInput:resultB completion:^(id resultC) {
completionHandler(resultC);
}];
}
else {
completionHandler(resultB); // error;
}
}];
}
else {
completionHandler(resultA); // error
}
}];
}
-Class1
、Class2
和Class3
都是UIViewController
-助手类
-内容显示类
他们做的事情大不相同,但共同的特点是他们与helper类的交互。它们以多种不同的方式从用户那里收集请求的详细信息,然后最终将请求发送到helper类。同步完成后,helper类将返回数据。然后,每个类将解释数据(XML文件),并通过segue将其传递给内容显示类 大致上是这样的: 类别1:
//Get user input
SomeData *data = [helperclass makerequest];
id vcData = [data process];
[self performSegueWithIdentifier:@"segueIdentifier"];
---
- (void)prepareForSegue:(UIStoryboardSegue *)segue
{
DestinationViewController *destination = (DestinationViewController *)segue.destinationViewController;
destination.data = vcData;
}
//Get user input
SomeData *data = [helperclass makerequestWithSender:self];
id vcData = [data process];
[self performSegueWithIdentifier:@"segueIdentifier"];
---
- (void)prepareForSegue:(UIStoryboardSegue *)segue
{
DestinationViewController *destination = (DestinationViewController *)segue.destinationViewController;
destination.data = vcData;
}
内容显示类:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.data presentdata];
}
现在看起来是这样的
我处理这个问题的方法是首先使它与Class1一起工作,以便将修复程序部署到class2和class3。那么class1和helper现在是这样交互的
类别1:
//Get user input
SomeData *data = [helperclass makerequest];
id vcData = [data process];
[self performSegueWithIdentifier:@"segueIdentifier"];
---
- (void)prepareForSegue:(UIStoryboardSegue *)segue
{
DestinationViewController *destination = (DestinationViewController *)segue.destinationViewController;
destination.data = vcData;
}
//Get user input
SomeData *data = [helperclass makerequestWithSender:self];
id vcData = [data process];
[self performSegueWithIdentifier:@"segueIdentifier"];
---
- (void)prepareForSegue:(UIStoryboardSegue *)segue
{
DestinationViewController *destination = (DestinationViewController *)segue.destinationViewController;
destination.data = vcData;
}
现在我面临的最大问题是如何将数据从helperclass返回到Class1
。我设法使它工作,通过这样做
(void)makeRequestWithSender:(Class1*)sender
{
[NSURLConnection sendAsynchronousRequest:...
{
[sender sendData:data];
}
}
然而,当我开始将它推广到另外两个GUI类时,它将构成我遇到困难的请求。我的第一个想法是设置sender:(id)
,但在告诉我id
没有方法sendData:
或类似方法时失败了
希望我在这里不是太含糊,你们可以帮忙。如果需要,我将能够发布代码片段,但目前有人能提供更好的建议,说明如何为此请求构造代码吗?我不完全清楚您现在如何处理数据,但要将数据更改为异步调用,我将使用块。例如,您当前的同步代码如下所示:
//Get user input
data = [helperclass makerequest]
sendData = [data process]
//Get user input
data = [helperclass makerequestWithSuccess:^{
sendData = [data process]
}];
-(void)makerequestWithSuccess:(void (^)(void))success{
// Put your makerequest code here
// After your makerequest is completed successfully, call:
success();
}
typedef (void)(^completion_block_t)(id result);
-(void) asyncTaskA:(completion_block_t)completionHandler;
-(void) asyncTaskBWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncTaskCWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler
{
[self asyncTaskA:^(id resultA){
if (![resultA isKindOfClass:[NSError class]]) {
[self asyncTaskBWithInput:resultA completion:^(id resultB){
if (![resultB isKindOfClass:[NSError class]]) {
[self asyncTaskCWithInput:resultB completion:^(id resultC) {
completionHandler(resultC);
}];
}
else {
completionHandler(resultB); // error;
}
}];
}
else {
completionHandler(resultA); // error
}
}];
}
会变成这样:
//Get user input
data = [helperclass makerequest]
sendData = [data process]
//Get user input
data = [helperclass makerequestWithSuccess:^{
sendData = [data process]
}];
-(void)makerequestWithSuccess:(void (^)(void))success{
// Put your makerequest code here
// After your makerequest is completed successfully, call:
success();
}
typedef (void)(^completion_block_t)(id result);
-(void) asyncTaskA:(completion_block_t)completionHandler;
-(void) asyncTaskBWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncTaskCWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler
{
[self asyncTaskA:^(id resultA){
if (![resultA isKindOfClass:[NSError class]]) {
[self asyncTaskBWithInput:resultA completion:^(id resultB){
if (![resultB isKindOfClass:[NSError class]]) {
[self asyncTaskCWithInput:resultB completion:^(id resultC) {
completionHandler(resultC);
}];
}
else {
completionHandler(resultB); // error;
}
}];
}
else {
completionHandler(resultA); // error
}
}];
}
使用成功块将允许您等待处理数据,直到makerequest
完成
新的makerequest
函数现在如下所示:
//Get user input
data = [helperclass makerequest]
sendData = [data process]
//Get user input
data = [helperclass makerequestWithSuccess:^{
sendData = [data process]
}];
-(void)makerequestWithSuccess:(void (^)(void))success{
// Put your makerequest code here
// After your makerequest is completed successfully, call:
success();
}
typedef (void)(^completion_block_t)(id result);
-(void) asyncTaskA:(completion_block_t)completionHandler;
-(void) asyncTaskBWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncTaskCWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler
{
[self asyncTaskA:^(id resultA){
if (![resultA isKindOfClass:[NSError class]]) {
[self asyncTaskBWithInput:resultA completion:^(id resultB){
if (![resultB isKindOfClass:[NSError class]]) {
[self asyncTaskCWithInput:resultB completion:^(id resultC) {
completionHandler(resultC);
}];
}
else {
completionHandler(resultB); // error;
}
}];
}
else {
completionHandler(resultA); // error
}
}];
}
希望这有帮助 我不确定我过去所做的是否与您的问题相关,但我所做的是创建一个下载类,该类具有一个
委托
协议,使用单个方法:-(void)downloadFinished:(id)data
任何需要获取异步数据的类,都会创建此下载类的实例,并将自身设置为
委托
。我调用downloadFinished:
从连接:didFailWithError:
和连接指定完成加载:
。然后,在委托中实现该方法时,我检查数据的类是NSData
还是NSError
,并评估该数据是否适合该类。您基本上希望使用“观察者模式”或(可能)稍微更改的设置,因此可以使用委托
观察者模式
您可以通过and获得机械师。您的3个不同UIViewController子类都订阅了特定的NSNotification,您可以通过NSNotificationCenter发布通知来通知他们
以下代码是如何处理viewcontroller子类中的问题的示例:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// subscribe to a specific notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomethingWithTheData:) name:@"MyDataChangedNotification" object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// do not forget to unsubscribe the observer, or you may experience crashes towards a deallocated observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
...
- (void)doSomethingWithTheData:(NSNotification *)notification {
// you grab your data our of the notifications userinfo
MyDataObject *myChangedData = [[notification userInfo] objectForKey:@"myChangedDataKey"];
...
}
在助手类中,数据更改后,您必须通知观察者,例如
-(void)myDataDidChangeHere {
MyDataObject *myChangedData = ...;
// you can add you data to the notification (to later access it in your viewcontrollers)
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyDataChangedNotification" object:nil userInfo:@{@"myChangedDataKey" : myChangedData}];
}
通过@protocol
假设您的所有UIViewController子类都驻留在父viewcontroller中,您可以在帮助器类中实现协议,并使父viewcontroller成为委托。然后,父视图控制器可以通过传递消息通知子UIViewController
您的助手类声明可以如下所示(假定为圆弧):
您的父viewcontroller需要是helper类的委托并实现其协议;宣言中的草图
@interface ParentViewController : UIViewController <HelperDelegate>
除了..
你可能会问自己更喜欢哪种方法。两者都是可行的,主要区别在于,通过观察者模式,可以“一次”通知更多对象,而协议只能有一个委托,如果需要,必须转发消息。关于赞成和反对意见有很多讨论。我建议你一旦下定决心,就仔细阅读它们(很抱歉,没有足够的声誉来发布两个以上的链接,所以请在stackoverflow上搜索)。如果有不清楚的地方,请询问。我不确定我是否正确理解了您的问题,但如果是:
//Get user input
data = [helperclass makerequest]
sendData = [data process]
//Get user input
data = [helperclass makerequestWithSuccess:^{
sendData = [data process]
}];
-(void)makerequestWithSuccess:(void (^)(void))success{
// Put your makerequest code here
// After your makerequest is completed successfully, call:
success();
}
typedef (void)(^completion_block_t)(id result);
-(void) asyncTaskA:(completion_block_t)completionHandler;
-(void) asyncTaskBWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncTaskCWithInput:(id)input completion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler;
-(void) asyncSomethingWithCompletion:(completion_block_t)completionHandler
{
[self asyncTaskA:^(id resultA){
if (![resultA isKindOfClass:[NSError class]]) {
[self asyncTaskBWithInput:resultA completion:^(id resultB){
if (![resultB isKindOfClass:[NSError class]]) {
[self asyncTaskCWithInput:resultB completion:^(id resultC) {
completionHandler(resultC);
}];
}
else {
completionHandler(resultB); // error;
}
}];
}
else {
completionHandler(resultA); // error
}
}];
}
你使用它就像:
[self asyncSomethingWithCompletion:^(id result){
if ([result isKindOfClass:[NSError class]]) {
NSLog(@"ERROR: %@", error);
}
else {
// success!
self.myData = result;
}
}];
“continuation”和错误处理让这有点混乱(Objective-C语法并没有真正增加可读性)
第三方库支持的另一个示例: 同样的逻辑可以这样写:
-(Promise*) asyncTaskA;
-(Promise*) asyncTaskBWithInput;
-(Promise*) asyncTaskCWithInput;
-(Promise*) asyncSomething;
- (Promise*) asyncSomething
{
return [self asyncTaskA]
.then(id^(id result) {
return [self asyncTaskBWithInput:result];
}, nil)
.then(id^(id result) {
return [self asyncTaskCWithInput:result];
}, nil);
}
其用途如下:
[self asyncSomething]
.then(^(id result) {
self.myData = result;
return nil;
},
^id(NSError* error) {
NSLog(@"ERROR: %@", error);
return nil;
});
如果您更喜欢后者,GitHub上提供了“Promise”框架:-我是作者;) 这里有一些合理的想法。要详细说明/补充我的意见: 首先,哪个对象应该告诉下载程序(
HelperClass
)开始下载?我的做法是在显示数据的视图控制器中执行此操作。因此,我通常在一段时间后启动网络请求(如在视图中将出现:
之前的