Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/107.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 在类/异步请求/iOS之间传递数据_Iphone_Ios_Objective C_Ipad_Oop - Fatal编程技术网

Iphone 在类/异步请求/iOS之间传递数据

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

我正在将我的应用程序从同步HTTP请求转换为异步HTTP请求,并且遇到了一个问题,看起来它需要对应用程序处理数据的方式进行大量修改。让我试着解释一下

以前是这样的,

//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上搜索)。如果有不清楚的地方,请询问。

我不确定我是否正确理解了您的问题,但如果是:

  • 异步启动任务A
  • 当任务A成功完成时,获取其结果并启动输入为结果A的任务B
  • 当任务B成功完成时,获取其结果并启动输入为结果B的任务C
  • 成功完成后,请高兴,否则打印错误
  • 代码示例如下所示:

    //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
    )开始下载?我的做法是在显示数据的视图控制器中执行此操作。因此,我通常在一段时间后启动网络请求(如在
    视图中将出现:
    之前的